The problem with TYPE var = args[c]; what do you write for type? Each i has a different type, so you cannot use a for loop like this.
Typically, the usual approach is to use recursion.
void f() { } //end loop template<class FirstType, typename...Args> void f(FirstType&& first, Args&&...rest) { //do loop body loop_body(std::forward<FirstType>(first)...) //do next "iteration" f(std::forward<Args>(rest)...); }
There is also this way to do this without recursion, but it is a bit more advanced:
template<typename...Args> void f(Args&&...args) { typedef int[] for_each; for_each{((void)( loop_body(std::forward<Args>(args)) ),0)...,0}; }
And finally, if you really want to access by index:
//note that "i" must be a compile time constant auto var = std::get<i>(std::tie(std::forward<Args>(args)...));
The
typedef int[] code
typedef int[] very strange, and so I will describe it here. We would like to call the function
loop_body(std::forward<Args>(args))...; but, unfortunately, parameter packages can only be expanded in certain contexts, and this is not one of them. The simplest and most obvious solution is to pass the results of all these calls to a function that does nothing:
do_nothing(loop_body(std::forward<Args>(args))...) , but unfortunately this is not suitable for return types
void types because you cannot create an instance of
void to pass to
do_nothing . Worse, he could call each of the functions in the wrong order. One way to "convert" the
void expression to something else is with a secret trick with the comma operator,
(func(), 0) executaes
func , and then "returns"
0 .
Worse, for reasons that I admittedly don't understand,
f(vs)...,0; and
(f(vs),0)...,0; are valid contexts for expanding parameter packages. However,
type array[] = {vs...} is a valid context. So now we have a way to combine this context with expressions with return values:
int array[] = {(f(vs),0)...}; And it works! Mainly!
If the parameter package has null types (yes, it really is, never forget it.), Then this leads to a compiler error. Therefore, we need to add one more zero to the end, therefore there is always at least one element:
int array[] = {(f(vs),0)..., 0}; . In addition, most compilers warn that
array is an unused variable. One way around this warning is to make the type temporary.
int a = (expr); is local, but
(int)(expr) creates an unnamed temporary. Therefore, we want
(int []){(f(vs),0)..., 0}; . For reasons that I cannot remember, this
(int[]) usually hidden behind a typedef. As a final detail, since some classes may overload the operator with a comma, it is safer to pass functions to
void :
int array[] = {((void)(f(vs)),0)..., 0};Unconnected, I have considered this macro in the past, which hides ugly details a bit more. But I feel that there is a flaw that I miss, otherwise it will be more common.
#define FOREACH_VARIADIC(EXPR) (int[]){((void)(EXPR),0)...,0} template<typename...Args> void f(Args&&...args) { FOREACH_VARIADIC(loop_body(std::forward<Args>(args))); }