Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic template pack expansion

I am trying to learn variadic templates and functions. I can't understand why this code doesn't compile:

template<typename T> static void bar(T t) {}  template<typename... Args> static void foo2(Args... args) {     (bar(args)...); }  int main() {     foo2(1, 2, 3, "3");     return 0;     } 

When I compile it fails with the error:

Error C3520: 'args': parameter pack must be expanded in this context

(in function foo2).

like image 804
Viacheslav Dronov Avatar asked Sep 05 '14 07:09

Viacheslav Dronov


People also ask

What is Variadic template in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

What is Pack expansion?

Pack expansion A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order.

What is ellipsis in c++?

Ellipsis in C++ allows the function to accept an indeterminate number of arguments. It is also known as the variable argument list. Ellipsis tells the compiler to not check the type and number of parameters the function should accept which allows the user to pass the variable argument list.

What is Variadic function in C?

Variadic functions are functions that can take a variable number of arguments. In C programming, a variadic function adds flexibility to the program. It takes one fixed argument and then any number of arguments can be passed.


1 Answers

One of the places where a pack expansion can occur is inside a braced-init-list. You can take advantage of this by putting the expansion inside the initializer list of a dummy array:

template<typename... Args> static void foo2(Args &&... args) {     int dummy[] = { 0, ( (void) bar(std::forward<Args>(args)), 0) ... }; } 

To explain the content of the initializer in more detail:

{ 0, ( (void) bar(std::forward<Args>(args)), 0) ... };   |       |       |                        |     |   |       |       |                        |     --- pack expand the whole thing    |       |       |                        |      |       |       --perfect forwarding     --- comma operator   |       |   |       -- cast to void to ensure that regardless of bar()'s return type   |          the built-in comma operator is used rather than an overloaded one   |   ---ensure that the array has at least one element so that we don't try to make an      illegal 0-length array when args is empty 

Demo.

An important advantage of expanding in {} is that it guarantees left-to-right evaluation.


With C++17 fold expressions, you can just write

((void) bar(std::forward<Args>(args)), ...); 
like image 73
T.C. Avatar answered Oct 12 '22 01:10

T.C.