2012-03-29 18 views
12

Ich habe ein Visual Studio 2008 C++ - Projekt, wo ich ein Strukturelement eines Vektors dieses Strukturtyps in einen neuen Vektor kopieren möchte. Zum Beispiel:Auswählen eines einzelnen Members aus jeder Struktur in einem Std :: Vektor in einen anderen Vektor

struct Foo { 
    int a; 
    long b; 
}; 

std::vector<Foo> v1; 
std::vector<long> v2; 

for(std::vector<Foo>::const_iterator it = v1.begin(); it != v1.end(); ++it) 
{ 
    v2.push_back(it->b); 
} 

Gibt es einen besseren/eleganteren Weg als dies?

Danke, PaulH

Antwort

16

In Visual C++ 2008, nein, das ist ungefähr so ​​"elegant", wie es nur geht. Die Standardbibliothek stellt Algorithmen zur Verfügung, mit denen Container manipuliert werden können. In den meisten Szenarien - besonders in einfachen Anwendungsfällen wie diesem - sind sie jedoch viel zu umständlich zu verwenden.

C++ 11 fügt Lambda-Ausdrücke zu C++ hinzu. Visual C++ 2010 und aktuelle Versionen anderer C++ - Compiler unterstützen diese C++ 11-Funktion. Mit Lambda-Ausdrücke, können Sie leicht den transform Algorithmus für die Aufgabe verwenden:

std::transform(v1.begin(), v1.end(), std::back_inserter(v2), 
       [](Foo const& x) { return x.b; }); 

ohne Lambda-Ausdrücke, dann würden Sie eine Funktion zum Extrahieren der b Element aus der Struktur definieren müssen:

long get_b(Foo const& x) { return x.b; } 

Sie könnten dann diese Funktion mit dem transform Algorithmus verwenden:

std::transform(v1.begin(), v1.end(), std::back_inserter(v2), get_b); 

jedoch für einfache Anwendungsfälle wie diese, kann diese qu Dies führt zu einem unhandlichen Code, da es schwierig ist, alle verwandten Funktionen zusammen zu halten.

+0

Und natürlich gibt es andere Techniken, wie Boost.Lambda, oder das Schreiben von Allzwecktransformatoren und deren Verwendung mit den Standardbibliotheksbindern, aber keine dieser Techniken könnte als eleganter angesehen werden als im ursprünglichen Code . –

+2

Sie können auch 'std :: bind (& Foo :: b)' verwenden, um eine Signaturfunktion 'long & (Foo &)' zu bekommen, denke ich. –

+0

Ich habe versucht, 'bind' komplett aus meinem Gedächtnis zu verbannen, obwohl ich fürchte, dass einige Narben für immer bestehen bleiben. : -O –

1

Es hängt wirklich davon ab, was Sie mit "besser" meinen.

Wenn Sie meinen, wenn das gleiche durch die Verwendung Vorlage List geschrieben werden kann, dann ist die Antwort ja:

template<typename C, typename T> 
struct MemberGetter 
{ 
    T C::*mp; 
    MemberGetter(T C::*mp) : mp(mp) { } 
    T operator()(const C& c) { return c.*mp; } 
}; 

struct Foo 
{ 
    double dm; 
}; 

... 
std::vector<double> x; 
std::vector<Foo> y; 

std::transform(y.begin(), y.end(), 
       std::back_inserter(x), 
       MemberGetter<Foo, double>(&Foo::dm)); 

Dies ist meiner Meinung nach schlimmer als eine explizite Schleife, hat aber den Vorteil, dass der Elementzeiger (dh welcher Teil der Struktur, die Sie kopieren) kann ein Laufzeitparameter sein.

Wenn das Element, das Sie kopieren müssen, stattdessen bekannt und behoben ist, würde ich sagen, dass die explizite Schleife der beste Weg ist (ich kann mir kaum vorstellen, in Fällen, in denen der Elementzeiger ein Vorlagenparameter ist macht irgendeinen Sinn).

Verwandte Themen