假设我有以下结构:
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个字段,因此为每个字段编写方法有点令人生畏和不优雅.
使用std::transform、std::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。
所以为每个字段编写一个方法有点令人生畏和不优雅
立即解决此问题的方法是将字段标识符作为参数传递.
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库动态编写.投影是一个非常常见的操作范围,因此许多以范围为中心的图书馆都有设施来完成它.