从结构的向量中,获取一个向量,该向量收集每个结构的一个字段

Adr*_*ian 5 c++

假设我有以下结构:

struct Point {
    double X,Y,Z;
};
Run Code Online (Sandbox Code Playgroud)

和以下向量:

std::vector<Point> v;
// populate v with random points
Run Code Online (Sandbox Code Playgroud)

现在,我想调用类似的东西collect(v, X)并获取std::vector包含X原始结构向量中的值的内容,例如:

v.push_back(Point{1.0, 2.0,  3.0});
v.push_back(Point{1.1, 0.0, -0.5});
auto ans = collect(v,X);
// ans = [1.0, 1.1]
Run Code Online (Sandbox Code Playgroud)

我认为这是一个非常常见的任务,我确信这个名字很好,我在问的时候无法想出(随意指出我!).

我可以做这个:

std::vector<double> collectX(std::vector<Point> v) {
    std::vector<double> output;
    for (auto elem : v) {
        output.push_back(elem.X);
    }
}
/* Repeat for each field the struct Point has... */
Run Code Online (Sandbox Code Playgroud)

我知道C++没有反思.我想知道是否有解决方法?正如您可能想象的那样,我正在使用的结构不只有3个字段,因此为每个字段编写方法有点令人生畏和不优雅.

j6t*_*j6t 6

使用std::transformstd::back_inserter、 和std::mem_fn

#include <functional>
//...
std::vector<Point> v{{0,1,2},{9,8,7}};

std::vector<double> x;

std::transform(v.begin(), v.end(), std::back_inserter(x),
           std::mem_fn(&Point::x));
Run Code Online (Sandbox Code Playgroud)

编译器通常可以优化掉后面的间接std::mem_fn


Sto*_*ica 5

所以为每个字段编写一个方法有点令人生畏和不优雅

立即解决此问题的方法是将字段标识符作为参数传递.

std::vector<double> collect(double Point::* f, std::vector<Point> const& v) {
    std::vector<double> output;
    for (auto const& elem : v) {
        output.push_back(elem.*f);
    }
    return output;
}
Run Code Online (Sandbox Code Playgroud)

被称为这样:

collect(&Point::X, v);
Run Code Online (Sandbox Code Playgroud)

如果类型不是总是double,那么上面的代码可以很容易地成为模板:

template<typename T>
std::vector<T> collect(T Point::* f, std::vector<Point> const& v) {
    std::vector<T> output;
    for (auto const& elem : v) {
        output.push_back(elem.*f);
    }
    return output;
}
Run Code Online (Sandbox Code Playgroud)

最后,你正在寻找这种提取的术语是"投射".也就是说,在将一个函数投影到一个轴上时会得到什么,非常粗略地说.在我们的例子中,函数将向量的索引映射到a Point,并且投影在x轴上,就像它一样.

它也可以使用C++标准库或range-v3库动态编写.投影是一个非常常见的操作范围,因此许多以范围为中心的图书馆都有设施来完成它.