C ++ / STL: std :: transform с заданным шагом? - PullRequest
6 голосов
/ 19 марта 2010

У меня есть 1d массив, содержащий данные 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??

Ответы [ 4 ]

3 голосов
/ 19 марта 2010

Ответ не в том, чтобы изменить strMover, а в том, чтобы изменить итератор. Определите новый класс итератора, который переносит float *, но перемещается на 3 позиции при вызове operator++.

Вы можете использовать Boost Итератор перестановок и использовать нестрогую перестановку, которая включает только интересующий вас диапазон.

Если вы попытаетесь накатить свой собственный итератор, есть несколько уловок: чтобы оставаться строгим к стандарту, вам нужно тщательно подумать о том, что является правильным «конечным» итератором для такого итератора быстрого шага, так как наивная реализация будет весело шаг за пределы разрешенного «одного конца за концом» в темную область далеко за концом массива, куда указатели никогда не должны войти, опасаясь носовых демонов .

Но я должен спросить: почему вы храните массив 3d-точек как массив float с? Просто определите тип данных Point3D и вместо этого создайте его массив. Гораздо проще.

1 голос
/ 26 августа 2011

Это ужасно, люди говорили вам использовать вместо этого итераторы шага.Помимо невозможности использовать функциональные объекты из стандартной библиотеки с таким подходом, вы очень, очень усложняете компилятору производить многоядерную или sse-оптимизацию с использованием подобных костылей.Ищите «итератор шага» для правильного решения, например, в кулинарной книге c ++.

И вернемся к исходному вопросу ... используйте valarray и stride для моделирования многомерных массивов.

1 голос
/ 19 марта 2010

Ну, я решил использовать for_each вместо transform, любые другие решения приветствуются:

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>);
            }
    };

На первый взгляд, это решение с защитой потоков.

0 голосов
/ 10 июля 2014

используйте повышающие адаптеры. Вы можете получить итераторы из них. единственный недостаток - время компиляции.

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