2016-10-04 8 views
3

オブジェクトのベクトルが与えられた場合、そのメンバを抽出するためのエレガントな方法がありますか?私は現在forループを使用していますが、それを行う方法があればいいと思います。例、オブジェクトのベクトルから要素を抽出する

class Object { 

int x; 
float y; 

} 

vector<Object> obj; 
// Fill up obj 

vector<int> all_x = obj.x // Won't work obviously 

答えて

2

共変集約をサポートしていません(一般的にまたはC++)std::vectorとして、あなたが欲しいものを行うには構文的にはかなり方法はありません。あなたは大丈夫なら

class getx_iter : public vector<Object>::iterator 
{ 
public: 
    getx_iter(const vector<Object>::iterator &iter) : vector<Object>::iterator(iter) {} 
    int operator*() { return (*this)->x; } 
}; 

Working code example

あなたが本当ににしたい場合は、あなたがそのような新しいイテレータクラスを定義することができ、obj要素のxメンバーとall_xを初期化します空のvectorを初期化してから、std::transformをlabmdaに置き換えると、(@andarsが示唆するように)より明確なオプションになります。

またvector::reserve()back_inserterを使用することにより、余分な初期化を避けることができます:

xs.reserve(foos.size()); 
std::transform(foos.begin(), foos.end(), back_inserter(xs), [](Foo f){return f.x;}); 

xObjectのプライベートなメンバーであり、何のゲッターを持っていない一方で、それを抽出することは非常に難しいだろうということに気づきます。

1

私は本当に良い方法を考えることはできません。

もう1つの方法は、ラムダでstd::transformを使用することです。

#include <vector> 
#include <algorithm> 


class Foo { 
public: 
    Foo(int x_): x(x_) {} 
    int x; 
}; 

int main() { 
    std::vector<Foo> foos; 
    for (int i = 0; i<10; i++) { 
     foos.push_back(Foo(i)); 
    } 

    std::vector<int> xs; 
    xs.resize(foos.size()); 
    std::transform(foos.begin(), foos.end(), xs.begin(), [](Foo f){return f.x;}); 
} 
0

いくつかのテンプレートとマクロの魔法、そしてそれが動作:もちろん

#include <vector> 
#include <algorithm> 
using namespace std; 


class Foo { 
public: 
    Foo(int x_): x(x_) {} 
    int x; 
}; 

#define GETFIELD(type, field) [](const type & obj){return obj.field;} 

template<typename T,typename U, typename TMapper> 
void MapVector(vector<T>& src, vector<U>& dst, TMapper mapper) { 
    for (const auto& it: src) { 
     dst.push_back(mapper(it)); 
    } 
} 

#define MapVectorField(src, dst, field) MapVector(src, dst, GETFIELD(decltype(src)::value_type, field)) 

int main() { 
    vector<Foo> vFoo; 
    for (int i = 0; i < 10; i++) { 
     vFoo.push_back(Foo(i)); 
    } 

    vector<int> vX; 
    MapVector(vFoo, vX, GETFIELD(Foo, x)); 
    MapVectorField(vFoo, vX, x); 

    for (int i = 0; i < vX.size(); i++) { 
     printf("%d\n", vX[i]); 
    } 
} 

、それは関数である、または生産にusing namespace stdを書いて、MapVectorFieldマクロに名前を付けるために非常に良いではありませんことを覚えておいてください。 range-v3

+0

あなたが代わりにあなたのマクロのメンバーポインタを使用することができます: '&フー:: X '。 – Jarod42

3

、それは単に

std::vector<int> xs = objs | ranges::view::transform(&Object::x); 

か、単にビューを使用して次のようになります。

auto xs = objs | ranges::view::transform(&Object::x); 

Demo

関連する問題