What's va_arg() in C++11 variadic template?
c++, c++11, clang, templates, variadic-templates
Solution
The problem is with `TYPE var = args[c];`, what do you write for `TYPE`? Each `i` has a different type, so you won't be able to use a `for` loop like this.
Generally, the normal 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's also this way to do it without recursion, but it's 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 one 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 is very strange, and so I'll lay it out here. We'd like to call a function `loop_body(std::forward<Args>(args))...;` but unfortunately, parameter packs can only be expanded in certain contexts, and that's not one of them. The easiest and most obvious solution is to pass the results of all those calls to a function that does nothing: `do_nothing(loop_body(std::forward<Args>(args))...)`, but unfortunately, this fails for `void` return types, because you can't instantiate a `void` to pass to the `do_nothing`. Worse, it could call each of the functions in the wrong order. One way to "convert" a `void` expression to something else is with an arcane 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;` nor `(f(vs),0)...,0;` are valid contexts for expanding parameter packs. 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! Mostly! If the parameter pack has zero types (yes, that's valid. never forget it.), then this results in a compiler error. So we have to add one additional zero on the end so there is always at least one element: `int array[] = {(f(vs),0)..., 0};`. Also, most compilers warn that `array` is an unused variable. One way to bypass that warning is to make the type a temporary. `int a = (expr);` is a local, but `(int)(expr)` creates an unnamed temporary. So we want `(int []){(f(vs),0)..., 0};`. For reasons I can't recall, this `(int[])` normally hidden behind a typedef. As a final detail, since some classes can overload the comma operator, it's safest to cast the functions to `void`: `int array[] = {((void)(f(vs)),0)..., 0};`
Unrelated, I've contemplated this macro in the past, which hides the ugly details a little more. But I feel like there's a downside I'm overlooking or else it would 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)));
}
Problem
I've read some articles about this new C++11 feature but I didn't understand all stuff (I'm new to C++). How do I access a specific argument like I can do using `va_arg` from `stdarg.h` in C? ``` template <typename ... Args> void f(Args ... args) { for(size_t i = 0; i < sizeof ...(args); i++) { // obviously, args...[i] didn't work... } } ```