C++/STL:std::transform 给定的步幅?

发布于 2024-08-25 08:52:56 字数 316 浏览 3 评论 0原文

我有一个包含 Nd 数据的一维数组,我想用 std::transform 或 std::for_each 有效地遍历它。

unigned int nelems;
unsigned int stride=3;// we are going to have 3D points
float *pP;// this will keep xyzxyzxyz...
Load(pP);
std::transform(pP, pP+nelems, strMover<float>(pP, stride));//How to define the strMover??

I have a 1d array containing Nd data, I would like to effectively traverse on it with std::transform or std::for_each.

unigned int nelems;
unsigned int stride=3;// we are going to have 3D points
float *pP;// this will keep xyzxyzxyz...
Load(pP);
std::transform(pP, pP+nelems, strMover<float>(pP, stride));//How to define the strMover??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

千纸鹤带着心事 2024-09-01 08:52:57

好吧,我决定使用 for_each 而不是转换,欢迎任何其他决定:

generator<unsigned int> gen(0, 1);
            vector<unsigned int> idx(m_nelem);//make an index
            std::generate(idx.begin(), idx.end(),gen);
            std::for_each(idx.begin(), idx.end(), strMover<float>(&pPOS[0],&m_COM[0],stride));

template<class T> T op_sum (T i, T j) { return i+j; }
template<class T> 
class strMover
    {
    T *pP_;
    T *pMove_;
    unsigned int stride_;
    public:
        strMover(T *pP,T *pMove, unsigned int stride):pP_(pP), pMove_(pMove),stride_(stride)
            {}
        void operator() ( const unsigned int ip )
            {
            std::transform(&pP_[ip*stride_], &pP_[ip*stride_]+stride_, 
                pMove_, &pP_[ip*stride_], op_sum<T>);
            }
    };

第一眼看,这是一个线程安全的解决方案。

Well, I have decided to use for_each instead of transform any other decisions are welcome:

generator<unsigned int> gen(0, 1);
            vector<unsigned int> idx(m_nelem);//make an index
            std::generate(idx.begin(), idx.end(),gen);
            std::for_each(idx.begin(), idx.end(), strMover<float>(&pPOS[0],&m_COM[0],stride));

where

template<class T> T op_sum (T i, T j) { return i+j; }
template<class T> 
class strMover
    {
    T *pP_;
    T *pMove_;
    unsigned int stride_;
    public:
        strMover(T *pP,T *pMove, unsigned int stride):pP_(pP), pMove_(pMove),stride_(stride)
            {}
        void operator() ( const unsigned int ip )
            {
            std::transform(&pP_[ip*stride_], &pP_[ip*stride_]+stride_, 
                pMove_, &pP_[ip*stride_], op_sum<T>);
            }
    };

From first look this is a thread safe solution.

会发光的星星闪亮亮i 2024-09-01 08:52:57

使用升压适配器。你可以从中得到迭代器。唯一的缺点是编译时间。

vector<float> pp = vector_load(pP);
boost::for_each(pp|stride(3)|transformed(dosmtn()));

use boost adapters. you can get iterators out of them. the only disadvantage is compilation time.

vector<float> pp = vector_load(pP);
boost::for_each(pp|stride(3)|transformed(dosmtn()));
尤怨 2024-09-01 08:52:56

答案不是改变 strMover,而是改变你的迭代器。定义一个新的迭代器类,它包装一个 float * 但在调用 operator++ 时向前移动 3 个位置。

您可以使用 boost 的 排列迭代器 并使用一个非严格排列,仅包括您感兴趣的范围。

如果您尝试推出自己的迭代器,则会遇到一些问题:为了严格遵守标准,您需要仔细考虑这样的正确的“结束”迭代器stride 迭代器是这样的,因为天真的实现会愉快地跨过允许的“one-past-the-end”,到达远远超过数组末尾的模糊区域,指针永远不应该进入该区域,因为担心 鼻恶魔

但我不得不问:为什么首先要将 3d 点数组存储为 float 数组?只需定义一个 Point3D 数据类型并创建一个数组即可。简单多了。

The answer is not to change strMover, but to change your iterator. Define a new iterator class which wraps a float * but moves forward 3 places when operator++ is called.

You can use boost's Permutation Iterator and use a nonstrict permutation which only includes the range you are interested in.

If you try to roll your own iterator, there are some gotchas: to remain strict to the standard, you need to think carefully about what the correct "end" iterator for such a stride iterator is, since the naive implementation will merrily stride over and beyond the allowed "one-past-the-end" to the murky area far past the end of the array which pointers should never enter, for fear of nasal demons.

But I have to ask: why are you storing an array of 3d points as an array of floats in the first place? Just define a Point3D datatype and create an array of that instead. Much simpler.

疾风者 2024-09-01 08:52:56

这太糟糕了,人们告诉你改用跨步迭代器。除了无法通过这种方法使用标准库中的函数对象之外,还使编译器通过使用这样的拐杖来生成多核或 sse 优化变得非常非常复杂。
寻找“跨步迭代器”以获得正确的解决方案,例如在 C++ 食谱中。

回到原来的问题...使用 valarray 和 stride 来模拟多维数组。

This is terrible, people told you to use stride iterators instead. Apart from not being able to use functional objects from standard library with this approach, you make it very, very complicated for compiler to produce multicore or sse optimization by using crutches like this.
Look for "stride iterator" for proper solution, for example in c++ cookbook.

And back to original question... use valarray and stride to simulate multidimensional arrays.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文