2012-07-27 75 views
7

給定一個保存MyClass的對象的std::vector。如何使用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 2012-07-27 11:37:43

+0

哇很多的答案,thx! – Nils 2012-07-27 11:40:58

回答

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在工作..但它也可以做W/O lambda。 – Nils 2012-07-27 11:39:08

+0

在使用'std :: back_inserter'之前,最好在'vec2'上調用'reserve()'。 – Nawaz 2012-07-27 11:39:20

+1

你可以使用'std :: bind'和'std :: transform'來跳過整個'AGetter'。 – Flexo 2012-07-27 11:40:04

4

你想用std::transformstd::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,爲什麼不使用lambda而不是'std :: bind'? – Nawaz 2012-07-27 11:40:45

+0

對於簡單的事情,我個人比較喜歡binder語法。令人遺憾的是佔位符擁有自己的命名空間,但即使如此,它也不如等效的lambda繁瑣。 – Flexo 2012-07-27 11:58:14