Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the rules for the "..." token in the context of variadic templates?

In C++11 there are variadic templates like this one:

template< class T, class... Args > unique_ptr<T> make_unique( Args&&... args ) {     return unique_ptr<T>(new T(std::forward<Args>(args)...)); } 

There are some curiosities about this: The expression std::forward<Args>(args)... uses both Args and args but only one ... token. Furthermore std::forward is a non-variadic template function taking only one template parameter and one argument. What are the syntax rules for that (roughly)? How can it be generalized?

Also: In the function implementation the ellipsis (...) is at the end of the expression of interest. Is there a reason that in the template argument list and the parameter list the ellipsis is in the middle?

like image 847
Ralph Tandetzky Avatar asked Jul 15 '13 10:07

Ralph Tandetzky


People also ask

What is the use of Variadic templates?

With the variadic templates feature, you can define class or function templates that have any number (including zero) of parameters. To achieve this goal, this feature introduces a kind of parameter called parameter pack to represent a list of zero or more parameters for templates.

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.

What is parameter pack in c++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.


1 Answers

In the context of variadic template, the ellipsis ... is used to unpack the template parameter pack if it appears on the right side of an expression (call this expression pattern for a moment), or it's a pack argument if it appears on left side of the name:

...thing  // pack   : appears as template arguments thing...  // unpack : appears when consuming the arguments 

The rule is that whatever pattern is on the left side of ... is repeated — the unpacked patterns (call them expressions now) are separated by comma ,.

It can be best understood by some examples. Suppose you have this function template:

template<typename ...T> //pack void f(T ... args)      //pack {    // here are unpack patterns     g( args... );        //pattern = args    h( x(args)... );     //pattern = x(args)    m( y(args...) );     //pattern = args (as argument to y())    n( z<T>(args)... );  //pattern = z<T>(args) } 

Now if I call this function passing T as {int, char, short}, then each of the function call is expanded as:

g( arg0, arg1, arg2 );            h( x(arg0), x(arg1), x(arg2) ); m( y(arg0, arg1, arg2) ); n( z<int>(arg0), z<char>(arg1), z<short>(arg2) ); 

In the code you posted, std::forward follows the fourth pattern illustrated by n() function call.

Note the difference between x(args)... and y(args...) above!


You can use ... to initialize an array also as:

struct data_info {      boost::any  data;      std::size_t type_size; };  std::vector<data_info> v{{args, sizeof(T)}...}; //pattern = {args, sizeof(T)} 

which is expanded to this:

std::vector<data_info> v  {     {arg0, sizeof(int)},    {arg1, sizeof(char)},    {arg2, sizeof(short)} }; 

I just realized a pattern could even include access specifier such as public, as shown in the following example:

template<typename ... Mixins> struct mixture : public Mixins ...  //pattern = public Mixins {     //code }; 

In this example, the pattern is expanded as:

struct mixture__instantiated : public Mixin0, public Mixin1, .. public MixinN   

That is, mixture derives publicly from all the base classes.

Hope that helps.

like image 195
Nawaz Avatar answered Oct 11 '22 20:10

Nawaz