Home > front end >  decouple member variables of a struct in variadic function accordingly
decouple member variables of a struct in variadic function accordingly

Time:05-09

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.

  • Related