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?
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). 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:
Now if I call this function passing
T
as{int, char, short}
, then each of the function call is expanded as:In the code you posted,
std::forward
follows the fourth pattern illustrated byn()
function call.Note the difference between
x(args)...
andy(args...)
above!You can use
...
to initialize an array also as:which is expanded to this:
I just realized a pattern could even include access specifier such as
public
, as shown in the following example:In this example, the pattern is expanded as:
That is,
mixture
derives publicly from all the base classes.Hope that helps.
The following is taken from the talk "Variadic Templates are Funadic" by Andrei Alexandrescu at GoingNative 2012. I can recommend it for a good introduction on variadic templates.
There are two things one can do with a variadic pack. It's possible to apply
sizeof...(vs)
to get the number of elements and expand it.Expansion rules
Expansion proceeds inwards outwards. When expanding two lists in lock-step, they have to have the same size.
More examples:
Expands all
Ts
in the template argument list ofA
and then the functionhun
gets expanded with allvs
.Expands all
Ts
in the template argument list ofA
and allvs
as the function arguments forhun
.Expands the function
hun
withTs
andvs
in lock-step.Note:
Ts
is not a type andvs
is not a value! They are aliases for a list of types/values. Either list may be potentially empty. Both obey only specific actions. So the following is not possible:Expansion loci
Function arguments
Initializer lists
Base specifiers
Member initializer lists
Tempate argument lists
Will only compile if there is a possible match for the arguments.
Capture lists
Attribute lists
It is in the specification, but there is no attribute that can be expressed as a type, yet.