I have posted a question before, unpack variadic arguments and pass it's elements accordingly. However, it didn't quite address my problem as I am not asking it precisely. Hence I would like to rephrase and explain my problem in detail. Thanks in advance!
suppose I got a struct Outcome
that take a two parameter function Outcome cal_out(int, int)
to construct, and can recursively compute by Outcome cal_out(Outcome, int, int)
with two additional parameters, i.e. x
and y
.
struct Outcome {
int valueX;
};
Outcome cal_out(int x,int y) {
int z = some_algo(x, y);
return Outcome{z};
}
Outcome cal_out(Outcome rhs, int x, int y){
int z = some_algo(rhs, x, y);
return Outcome {z};
}
template<class... Ts>
Outcome cal_out(Outcome rhs, int x, int y, Ts... ts){
return cal_out(cal_out(rhs, x, y), ts...);
}
And now my problem is that, I got a struct Coord
like this.
template<int X, int Y>
struct Coord {
static const int valueX = X;
static const int valueY = Y;
};
I would like to ask how to call get_out_from_coords()
to get the outcome i.e.
Outcome out = get_out_from_coords<Coord<1,2>, Coord<3,4>, Coord<5,6> >();
with my pseudo implementation that doesn't work
template<class COORD>
Outcome get_out_from_coords() {
return cal_out(COORD::valueX, COORD::valueY);
}
template<class COORD1, class COORD2>
Outcome get_out_from_coords() {
return cal_out(get_out_from_coords<COORD1>(), COORD2::valueX, COORD2::valueY);
}
template<class COORD1, class COORD2, class... COORDs>
Outcome get_out_from_coords() {
return cal_out( get_out_from_coords<COORD1, COORD2>(), COORDs::valueX, COORDs::valueY...);
//manipulating the pack expressions to get something like this
}
Noted: Outcome
cannot calculate in this way Outcome cal_out(Outcome, Outcome)
So, something like fold expression wouldn't work in this case. i.e.
template<class... COORDs>
Outcome get_out_from_coords() {
return cal_out(cal_out(COORDs::valueX, COORDs::valueY)...);
}
CodePudding user response:
template<class... COORDs>
Outcome get_out_from_coords() {
return std::apply(
[](int x, int y, auto... args){ return cal_out(cal_out(x, y), args...); },
std::tuple_cat(std::make_tuple(COORDs::valueX, COORDs::valueY)...)
);
}
This just concatenates all of the valueX
/valueY
pairs and calls cal_out
with these arguments. This assumes here that everything is by-value and that copying arguments is cheap. If these conditions are not satisfied std::forward_as_tuple
and perfect-forwarding in the lambda should be used.
I also feel that cal_out
is defined in a strange way. I think there should be a variadic overload not requiring a Outcome
, which could then be called with
[](auto... args){ return cal_out(args...); }
as lambda instead. Otherwise you would need to add special cases if there is only one COORDs
.