オブジェクトのベクトルが与えられた場合、そのメンバを抽出するためのエレガントな方法がありますか?私は現在forループを使用していますが、それを行う方法があればいいと思います。例、オブジェクトのベクトルから要素を抽出する
class Object {
int x;
float y;
}
vector<Object> obj;
// Fill up obj
vector<int> all_x = obj.x // Won't work obviously
オブジェクトのベクトルが与えられた場合、そのメンバを抽出するためのエレガントな方法がありますか?私は現在forループを使用していますが、それを行う方法があればいいと思います。例、オブジェクトのベクトルから要素を抽出する
class Object {
int x;
float y;
}
vector<Object> obj;
// Fill up obj
vector<int> all_x = obj.x // Won't work obviously
共変集約をサポートしていません(一般的にまたは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; }
};
:
あなたが本当ににしたい場合は、あなたがそのような新しいイテレータクラスを定義することができ、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;});
もx
がObject
のプライベートなメンバーであり、何のゲッターを持っていない一方で、それを抽出することは非常に難しいだろうということに気づきます。
私は本当に良い方法を考えることはできません。
もう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;});
}
いくつかのテンプレートとマクロの魔法、そしてそれが動作:もちろん
#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で
、それは単に
std::vector<int> xs = objs | ranges::view::transform(&Object::x);
か、単にビューを使用して次のようになります。
auto xs = objs | ranges::view::transform(&Object::x);
あなたが代わりにあなたのマクロのメンバーポインタを使用することができます: '&フー:: X '。 – Jarod42