Let's say I have the following struct:
struct Point {
double X,Y,Z;
};
and the following vector:
std::vector<Point> v;
// populate v with random points
Now, I want to call something like collect(v, X)
and get a std::vector
that contains the X
values from the original struct vector in it, for example:
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]
I think this is a pretty common task, and I'm sure there's a good name for this that I couldn't come up with while asking (feel free to point me out!).
I can do this:
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... */
I know C++ has no reflection. I was wondering if there's a workaround for this? As you may imagine, the struct I am working with doesn't have just 3 fields, so writing a method for each fields is a bit daunting and inelegant.
Use std::transform
, std::back_inserter
, and 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));
Compilers can typically optimize away the indirection behind std::mem_fn
.
so writing a method for each fields is a bit daunting and inelegant
An immediate fix for that is to pass the field identifier as an argument too.
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;
}
To be called like this:
collect(&Point::X, v);
If the types aren't always double
, then the above can easily be made a template over the member type:
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;
}
And finally, the term you are looking for this sort of extraction is "projection". I.e, what one gets when projecting a function onto an axis, very roughly speaking. In our case, the function maps an index of the vector to a Point
, and the projection is onto the x
axis, as it were.
It can also be written on the fly with the C++ standard library, or with the ranges-v3 library. Projection is a very common operation with ranges of items, so many range-centric libraries will have the facilities to do it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With