开发者

C++/STL: std::transform with given stride?

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 goin开发者_高级运维g 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??


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.


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.


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.


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()));
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜