2012-07-27 2 views
7

std::vector에는 MyClass의 객체가 들어 있습니다. std::copy을 사용하여 MyClass의 한 멤버의 데이터 만 보유하는 다른 벡터를 만들려면 어떻게해야합니까? 나는 사용자 정의 back_inserter을 구현해야한다고 생각하지만, 지금까지 이것을 수행하는 방법을 이해할 수 없었다.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'는 요소를 수정하지 않고 일반 복사를위한 것입니다. 'std :: transform'을 사용하면 각 요소에 변형을 적용한 다음 변환 결과를 저장할 수 있습니다. 정확히 당신이 원하는 것입니다. :) – jalf

+0

놀랍게도 많은 답변이 있습니다. – Nils

답변

15

Use std::transform입니다.

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

(당신이, 당신이 만들 수있는 C++ (11)를 사용할 수없는 경우 함수가 자신을 반대 :

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

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

또는 사용할 수있는 경우 std::tr1::bind를 사용 TR1 :

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

@Nawaz가 아래에 언급했듯이 불필요한 재 할당을 방지하기 위해 .reserve()을 수행하십시오.

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

나는 직장에서 C++ 11을 가지고 있었으면 좋겠지 만 람다 없이도 할 수있다. – Nils

+0

'std :: back_inserter'를 사용하기 전에'vec2'에'reserve()'를 호출하는 것이 낫습니다. – Nawaz

+1

'std :: bind'를'std :: transform'과 함께 사용하면 전체'AGetter'를 건너 뛸 수 있습니다. – Flexo

4

당신은 멤버 변수에 대한 포인터에 바인딩 std::transform하지 std::copystd::bind를 사용하려면 :

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

내 예제는 C++ 11이지만, 당신이 편리 벡터 initalization를 건너 뛸 경우 대신 boost::bind을 사용하십시오.이 방법은 C++ 11 없이도 잘 작동합니다.

+1

C++ 11을 사용한다면'std :: bind' 대신에 lambda를 사용하지 않을까? – Nawaz

+0

간단한 것들을 위해 저는 개인적으로 바인더 구문을 선호합니다. placeholder가 자신의 네임 스페이스를 갖게 된 것은 유감스러운 일입니다. 그러나 심지어 그것과 동등한 람다보다 덜 장황합니다. – Flexo

관련 문제