Reputation: 64997
Let's say I have a class composed of homogeneous types:
struct Homog {
int a;
double b;
std::string c;
};
Here's a function which calculates the "element-wise min"1 of two instances of this class:
Homog min(const Homog& l, const Homog& r) {
return {
std::min(l.a, r.a),
std::min(l.b, r.b),
std::min(l.c, r.c),
};
}
Great.
Now I want to calculate the max instead of the min. The code is identical, but with std::min
replaced with std::max
. I wouldn't want to duplicate it, rather I'd like to have one generic "element-wise apply" method, and then the min and max just call that with the appropriate functor:
Homog apply(const Homog& l, const Homog& r, ?? op) {
return {
op(l.a, r.a),
op(l.b, r.b),
op(l.c, r.c),
};
}
Homog min(const Homog& l, const Homog& r) {
return apply(l, r, std::min);
}
Homog max(const Homog& l, const Homog& r) {
return apply(l, r, std::max);
}
Of course, the above code doesn't work, because I don't know how to declare op
. It is not a normal generic functor object, because it needs to work on different types.
Can I do what I want to, somehow passing something which says "call op for each member: don't worry, it will resolve to something for each type"?
Maybe using min()
isn't the best name here, because it doesn't behave the same as std::min
which always returns one of the two given objects: this method returns a new object which in general is not the same as either of the two inputs, but rather a mix of their member values.
Upvotes: 1
Views: 90
Reputation: 66240
Of course, the above code doesn't work, because I don't know how to declare op. It is not a normal generic functor object, because it needs to work on different types.
This problem is usually bypassed using a functional, with a template operator()
.
Starting from C++14 (that introduce generic lambdas) simply as follows
template <typename F>
Homog apply(const Homog& l, const Homog& r, F const & op) {
return {
op(l.a, r.a),
op(l.b, r.b),
op(l.c, r.c),
};
}
Homog min(const Homog& l, const Homog& r) {
return apply(l, r, [](auto const & a, auto const & b){ return std::min(a, b); });
}
Upvotes: 2