A template parameter pack is a template parameter that accepts zero or more template arguments. [ Example:
template<class ... Types> struct Tuple { }; Tuple<> t0; // Types contains no arguments Tuple<int> t1; // Types contains one argument: int Tuple<int, float> t2; // Types contains two arguments: int and float Tuple<0> error; // error: 0 is not a type
— end example ]
A function parameter pack is a function parameter that accepts zero or more function arguments. [ Example:
template<class ... Types> void f(Types ... args); f(); // OK: args contains no arguments f(1); // OK: args contains one argument: int f(2, 1.0); // OK: args contains two arguments: int and double
— end example ]
A pack expansion consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list (described below). The form of the pattern depends on the context in which the expansion occurs. Pack expansions can occur in the following contexts:
In a function parameter pack ([dcl.fct]); the pattern is the parameter-declaration without the ellipsis.
In a using-declaration; the pattern is a using-declarator.
In a template parameter pack that is a pack expansion ([temp.param]):
if the template parameter pack is a parameter-declaration; the pattern is the parameter-declaration without the ellipsis;
if the template parameter pack is a type-parameter with a template-parameter-list; the pattern is the corresponding type-parameter without the ellipsis.
In an initializer-list; the pattern is an initializer-clause.
In a base-specifier-list; the pattern is a base-specifier.
In a mem-initializer-list for a mem-initializer whose mem-initializer-id denotes a base class; the pattern is the mem-initializer.
In a template-argument-list ([temp.arg]); the pattern is a template-argument.
In an attribute-list; the pattern is an attribute.
In an alignment-specifier ([dcl.align]); the pattern is the alignment-specifier without the ellipsis.
In a capture-list ([expr.prim.lambda]); the pattern is a capture.
In a sizeof... expression; the pattern is an identifier.
In a fold-expression; the pattern is the cast-expression that contains an unexpanded parameter pack.
[ Example:
template<class ... Types> void f(Types ... rest);
template<class ... Types> void g(Types ... rest) {
f(&rest ...); // “&rest ...” is a pack expansion; “&rest” is its pattern
}
— end example ]
For the purpose of determining whether a parameter pack satisfies a rule regarding entities other than parameter packs, the parameter pack is considered to be the entity that would result from an instantiation of the pattern in which it appears.
A parameter pack whose name appears within the pattern of a pack expansion is expanded by that pack expansion. An appearance of the name of a parameter pack is only expanded by the innermost enclosing pack expansion. The pattern of a pack expansion shall name one or more parameter packs that are not expanded by a nested pack expansion; such parameter packs are called unexpanded parameter packs in the pattern. All of the parameter packs expanded by a pack expansion shall have the same number of arguments specified. An appearance of a name of a parameter pack that is not expanded is ill-formed. [ Example:
template<typename...> struct Tuple {}; template<typename T1, typename T2> struct Pair {}; template<class ... Args1> struct zip { template<class ... Args2> struct with { typedef Tuple<Pair<Args1, Args2> ... > type; }; }; typedef zip<short, int>::with<unsigned short, unsigned>::type T1; // T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>> typedef zip<short>::with<unsigned short, unsigned>::type T2; // error: different number of arguments specified for Args1 and Args2 template<class ... Args> void g(Args ... args) { // OK: Args is expanded by the function parameter pack args f(const_cast<const Args*>(&args)...); // OK: “Args” and “args” are expanded f(5 ...); // error: pattern does not contain any parameter packs f(args); // error: parameter pack “args” is not expanded f(h(args ...) + args ...); // OK: first “args” expanded within h, // second “args” expanded within f }
— end example ]
The instantiation of a pack expansion that is neither a sizeof... expression nor a fold-expression produces a list E1,E2,…,EN, where N is the number of elements in the pack expansion parameters. Each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element. Such an element, in the context of the instantiation, is interpreted as follows:
if the pack is a template parameter pack, the element is a template parameter of the corresponding kind (type or non-type) designating the type or value from the template argument; otherwise,
if the pack is a function parameter pack, the element is an id-expression designating the function parameter that resulted from the instantiation of the pattern where the pack is declared.
All of the Ei become elements in the enclosing list. [ Note: The variety of list varies with the context: expression-list, base-specifier-list, template-argument-list, etc. — end note ] When N is zero, the instantiation of the expansion produces an empty list. Such an instantiation does not alter the syntactic interpretation of the enclosing construct, even in cases where omitting the list entirely would otherwise be ill-formed or would result in an ambiguity in the grammar. [ Example:
template<class... T> struct X : T... { }; template<class... T> void f(T... values) { X<T...> x(values...); } template void f<>(); // OK: X<> has no base classes // x is a variable of type X<> that is value-initialized
— end example ]
The instantiation of a sizeof... expression produces an integral constant containing the number of elements in the parameter pack it expands.
The instantiation of a fold-expression produces:
((E1 op E2) op ⋯) op EN for a unary left fold,
E1 op (⋯ op (EN−1 op EN)) for a unary right fold,
(((E op E1) op E2) op ⋯) op EN for a binary left fold, and
E1 op (⋯ op (EN−1 op (EN op E))) for a binary right fold.
In each case, op is the fold-operator, N is the number of elements in the pack expansion parameters, and each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element. For a binary fold-expression, E is generated by instantiating the cast-expression that did not contain an unexpanded parameter pack. [ Example:
template<typename ...Args> bool all(Args ...args) { return (... && args); } bool b = all(true, true, true, false);
Within the instantiation of all, the returned expression expands to ((true && true) && true) && false, which evaluates to false. — end example ] If N is zero for a unary fold-expression, the value of the expression is shown in Table 14; if the operator is not listed in Table 14, the instantiation is ill-formed.
Operator | Value when parameter pack is empty |
&& | true |
|| | false |
, | void() |