2

I have an interface wherein the types of the parameters mostly encode their own meanings. I have a function that takes one of these parameters. I'm trying to make a function that takes a set of these parameters and performs the function on each one in order.

#include <iostream>
#include <vector>

enum param_type{typeA,typeB};

template <param_type PT> struct Container{
  int value;
  Container(int v):value(v){}
};

int f(Container<typeA> param){
  std::cout<<"Got typeA with value "<<param.value<<std::endl;
  return param.value;
}
int f(Container<typeB> param){
  std::cout<<"Got typeB with value "<<param.value<<std::endl;
  return param.value;
}

My current solution uses a recursive variadic template to delegate the work.

void g(){}
template <typename T,typename...R>
void g(T param,R...rest){
  f(param);
  g(rest...);
}

I would like to use a packed parameter expansion, but I can't seem to get that to work without also using the return values. (In my particular case the functions are void.)

template <typename...T> // TODO: Use concepts once they exist.
void h(T... params){
  // f(params);...
  // f(params)...;    // Fail to compile.
  // {f(params)...};
  std::vector<int> v={f(params)...}; // Works
}

Example usage

int main(){
  auto a=Container<typeA>(5);
  auto b=Container<typeB>(10);
  g(a,b);
  h(a,b);
  return 0;
}

Is there an elegant syntax for this expansion in C++?

unDeadHerbs
  • 1,306
  • 1
  • 11
  • 19
  • Please choose: c++11 , c++14 or c++17? And you may have a look here [link](https://stackoverflow.com/questions/58588748/folding-of-template-parameter-packs-in-pre-c17-idiomatic-approach#comment103491591_58588748) –  Nov 05 '19 at 06:34
  • 1
    Probably you're looking for a comma operator and fold expression `(f(params) , ... )` – smitsyn Nov 05 '19 at 07:01
  • @smitsyn fold expressions are introduced in c++17. Your solution may not working depending on the standard used in question. – Empty Space Nov 05 '19 at 07:31

1 Answers1

4

In C++17: use a fold expression with the comma operator.

template <typename... Args>
void g(Args... args)
{
    ((void)f(args), ...);
}

Before C++17: comma with 0 and then expand into the braced initializer list of an int array. The extra 0 is there to ensure that a zero-sized array is not created.

template <typename... Args>
void g(Args... args)
{
    int arr[] {0, ((void)f(args), 0)...};
    (void)arr;                            // suppress unused variable warning
}

In both cases, the function call expression is cast to void to avoid accidentally invoking a user-defined operator,.

L. F.
  • 19,445
  • 8
  • 48
  • 82