2010-03-19 9 views
6

Ho un array 1d contenente dati Nd, vorrei attraversarlo efficacemente con std :: transform o std :: for_each.C++/STL: std :: transform con il passo specificato?

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?? 
+0

Cosa vuoi fare per 'strMover' (o l'intero' transform')? – jpalecek

+0

Ciao, ho bisogno di una trasformazione completa. Lo strMover ho scritto solo per illustrazione ... – Arman

risposta

1

Beh, ho deciso di utilizzare for_each invece di trasformare qualsiasi altra decisione sono i benvenuti:

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

dove

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

Da primo sguardo questa è una soluzione sicura thread.

3

La risposta è di non cambiare strMover, ma per cambiare il vostro iteratore. Definire una nuova classe iteratore che avvolge un float * ma avanza di 3 posizioni quando viene chiamato operator++. .

È possibile utilizzare Boost Permutation Iterator e utilizzare una permutazione nonstrict che comprende solo l'intervallo che ti interessa

Se si tenta di rotolare il proprio iteratore, ci sono alcuni trucchi: per rimanere rigorosa per lo standard, è necessario riflettere attentamente su quale sia il corretto iteratore di "fine" per un iteratore di tale passo, poiché l'implementazione ingenua andrà allegramente al di là del "one-past-end-end" consentito fino all'area oscura molto oltre la fine del array che i puntatori non dovrebbero mai inserire, per timore di nasal demons.

Ma devo chiederlo: perché memorizzi una serie di punti 3D come una serie di float s in primo luogo? Basta definire un tipo di dati Point3D e creare invece una matrice. Molto più semplice

+0

Avrei fatto +1 ma sono fuori, ma questo è quello che stavo per dire. Se c'è un bisogno, sono disposto a provare a scrivere gli iteratori la prossima volta che ho del tempo libero. – GManNickG

+0

Suppongo che dovrei notare che poiché un permutatore Iterator memorizza la sua permutazione come una lista, il permutatore Iterator non sarà un iteratore di accesso casuale. Non so se questo sarà un problema per la parallelizzazione di 'std :: transform' –

1

Questo è terribile, la gente ti ha detto di usare invece gli iteratori di passo. Oltre a non essere in grado di utilizzare oggetti funzionali dalla libreria standard con questo approccio, si rende molto, molto complicato per il compilatore produrre l'ottimizzazione multicore o sse usando stampelle come questa. Cerca "stride iterator" per la soluzione corretta, ad esempio nel ricettario C++.

E torna alla domanda originale ... usa valarray e passo per simulare array multidimensionali.

0

utilizzare adattatori boost. puoi far uscire gli iteratori da loro. l'unico svantaggio è il tempo di compilazione.

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