2012-07-27 11 views
7

Dato un std::vector che contiene oggetti di MyClass. Come posso creare un altro vettore che contiene solo i dati di un membro di MyClass utilizzando std::copy? Suppongo che avrei dovuto implementare una custom back_inserter ma non sono riuscito a capire come farlo finora.Inseritore personalizzato per std :: copy

struct MyClass { 
    int a; 
} 

std::vector<MyClass> vec1; 

// I could copy that to another vector of type MyClass using std::copy. 
std::copy(vec1.begin(), vec1.end(); std::back_inserter(someOtherVec) 

// However I want just the data of the member a, how can I do that using std::copy? 
std::vector<int> vec2; 
+1

'std :: copy' è per la copia semplice, senza modificare gli elementi. 'std :: transform' consente di applicare una trasformazione a ciascun elemento e quindi di memorizzare l'output della trasformazione. Che è esattamente quello che vuoi :) – jalf

+0

wow molte risposte, grazie! – Nils

risposta

15

Use std::transform per quello.

std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2), 
       [](const MyClass& cls) { return cls.a; }); 

(Se non è possibile utilizzare C++ 11, si potrebbe fare una funzione di oggetto da soli:

struct AGetter { int operator()(const MyClass& cls) const { return cls.a; } }; 

std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2), AGetter()); 

o utilizzare std::tr1::bind se è possibile utilizzare TR1:

std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2), 
       std::tr1::bind(&MyClass::a, std::tr1::placeholders::_1)); 

BTW, come commentato da @Nawaz di seguito, fare un .reserve() per evitare una ridistribuzione non necessaria durante la copia

vec2.reserve(vec1.size()); 
std::transform(...); 
+0

Vorrei avere C++ 11 al lavoro .. ma può anche essere fatto senza lambda. – Nils

+0

È meglio chiamare 'reserve()' su 'vec2' prima di usare' std :: back_inserter'. – Nawaz

+1

Puoi usare 'std :: bind' con' std :: transform' per saltare l'intero 'AGetter'. – Flexo

4

che si desidera utilizzare std::transform non std::copy e std::bind di legarsi a un puntatore a una variabile membro:

#include <algorithm> 
#include <iterator> 
#include <vector> 
#include <iostream> 
#include <functional> 

struct foo { 
    int a; 
}; 

int main() { 
    const std::vector<foo> f = {{0},{1},{2}}; 
    std::vector<int> out; 

    out.reserve(f.size()); 
    std::transform(f.begin(), f.end(), std::back_inserter(out), 
       std::bind(&foo::a, std::placeholders::_1)); 

    // Print to prove it worked: 
    std::copy(out.begin(), out.end(), std::ostream_iterator<int>(std::cout, "\n")); 
} 

Il mio esempio è C++ 11, ma se si salta il vettore di inizializzazione del portata di mano e utilizzare boost::bind invece funziona altrettanto bene senza C++ 11.

+1

Se stai usando C++ 11, perché non usare lambda invece di 'std :: bind'? – Nawaz

+0

Per cose semplici, preferisco personalmente la sintassi del raccoglitore. È un peccato che i segnaposto abbiano il loro spazio dei nomi, ma anche con quello è meno prolisso del lambda equivalente. – Flexo

Problemi correlati