2012-03-29 14 views
12

Mam projekt Visual Studio 2008 C++, w którym chciałbym skopiować jeden element struct wektora tego typu struct do nowego wektora. Na przykład:wybieranie pojedynczego elementu z każdej struktury w std :: vector do innego wektora

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

Czy istnieje lepszy/bardziej elegancki sposób niż to?

Dzięki, PaulH

Odpowiedz

16

W Visual C++ 2008, nie, to jest tak "elegancki", jak to się robi. Biblioteka standardowa udostępnia algorytmy, którymi można manipulować kontenerami, ale w większości przypadków - szczególnie w prostych przypadkach, takich jak ten - są one zbyt kłopotliwe w użyciu.

C++ 11 dodaje wyrażenia lambda do C++. Visual C++ 2010 i najnowsze wersje innych kompilatorów C++ obsługują tę funkcję C++ 11. Z wyrażeń lambda, można łatwo wykorzystać algorytm ten transform dla zadania:

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

Bez wyrażenia lambda, trzeba by zdefiniować funkcję wyodrębnić element b z struct:

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

następnie można użyć tej funkcji z algorytmem transform:

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

Jednakże dla prostych przypadków użycia, takich jak ten, to może qu ostro prowadzą do nieporęcznego kodu, ponieważ trudno jest starannie zachować wszystkie powiązane funkcje.

+0

Oczywiście, istnieją inne techniki, takie jak Boost.Lambda, lub pisanie transformatorów ogólnego zastosowania i używanie ich w segregatorach ze standardowej biblioteki, ale żadna z tych technik nie może być uważana za bardziej elegancka niż w oryginalnym kodzie . –

+2

Można również użyć 'std :: bind (& Foo :: b)', aby uzyskać funkcję sygnatury 'long & (Foo &)', jak sądzę. –

+0

Próbowałem całkowicie zablokować "bind" z mojej pamięci, choć obawiam się, że niektóre blizny pozostaną na zawsze. : -O –

1

To naprawdę zależy od tego, co masz na myśli mówiąc "lepiej".

Jeśli masz na myśli, jeśli to samo można zapisać za pomocą szablonu oszustwo to odpowiedź brzmi tak:

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

To jest moim zdaniem gorzej niż wyraźnego pętli, ale ma tę zaletę, że wskaźnik członkiem (tj. która część struktury, którą kopiujesz) może być parametrem wykonawczym.

Jeśli członek, którego chcesz skopiować, jest znany i poprawiony, powiedziałbym, że jawna pętla jest najlepszym sposobem (nie mogę sobie wyobrazić narożnych przypadków, w których za pomocą podobnego szablonu, gdzie wskaźnik członka jest parametrem szablonu ma sens).

Powiązane problemy