Files
2025-10-25 03:02:53 +03:00

21 KiB
Raw Permalink Blame History

[temp.variadic]

13 Templates [temp]

13.7 Template declarations [temp.decls]

13.7.4 Variadic templates [temp.variadic]

1

#

A template parameter pack is a template parameter that accepts zero or more template arguments.

[Example 1: template<class ... Types> struct Tuple { };

Tuple<> t0; // Types contains no arguments Tuple 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]

2

#

A function parameter pack is a function parameter that accepts zero or more function arguments.

[Example 2: template<class ... Types> void f(Types ... args);

f(); // args contains no arguments f(1); // args contains one argument: int f(2, 1.0); // args contains two arguments: int and double — end example]

3

#

An init-capture pack is a lambda capture that introduces an init-capture for each of the elements in the pack expansion of its initializer.

[Example 3: template <typename... Args>void foo(Args... args) {[...xs=args]{ bar(xs...); // xs is an init-capture pack};} foo(); // xs contains zero init-captures foo(1); // xs contains one init-capture — end example]

4

#

A structured binding pack is an sb-identifier that introduces zero or more structured bindings ([dcl.struct.bind]).

[Example 4: auto foo() -> int(&)[2];

template void g() {auto [...a] = foo(); // a is a structured binding pack containing two elementsauto [b, c, ...d] = foo(); // d is a structured binding pack containing zero elements} — end example]

5

#

A pack is a template parameter pack, a function parameter pack, an init-capture pack, or a structured binding pack.

The number of elements of a template parameter pack or a function parameter pack is the number of arguments provided for the parameter pack.

The number of elements of an init-capture pack is the number of elements in the pack expansion of its initializer.

6

#

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:

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; the pattern is the corresponding type-parameter without the ellipsis;

if the template parameter pack is a template template parameter; the pattern is the correspondingtype-tt-parameter,variable-tt-parameter, orconcept-tt-parameter without the ellipsis.

[Example 5: 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]

7

#

For the purpose of determining whether a pack satisfies a rule regarding entities other than packs, the pack is considered to be the entity that would result from an instantiation of the pattern in which it appears.

8

#

A pack whose name appears within the pattern of a pack expansion is expanded by that pack expansion.

An appearance of the name of a pack is only expanded by the innermost enclosing pack expansion.

The pattern of a pack expansion shall name one or more packs that are not expanded by a nested pack expansion; such packs are calledunexpanded packs in the pattern.

All of the packs expanded by a pack expansion shall have the same number of arguments specified.

An appearance of a name of a pack that is not expanded is ill-formed.

[Example 6: 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::with<unsigned short, unsigned>::type T2; // error: different number of arguments specified for Args1 and Args2template<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 packs f(args); // error: pack “args'' is not expanded f(h(args ...) + args ...); // OK, first “args'' expanded within h,// second “args'' expanded within f} — end example]

9

#

The instantiation of a pack expansion considers items E1,E2,…,EN, whereN 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 typedef-name for a type template parameter pack,

an id-expression for a constant template parameter pack, or

a template-name for a template template parameter pack

designating the ith corresponding type, constant, or template template argument;

if the pack is a function parameter pack, the element is anid-expression designating the ith function parameter that resulted from instantiation of the function parameter pack declaration;

if the pack is an init-capture pack, the element is an id-expression designating the variable introduced by the ith init-capture that resulted from instantiation of the init-capture pack declaration; otherwise

if the pack is a structured binding pack, the element is an id-expression designating the ith structured binding in the pack that resulted from the structured binding declaration.

When N is zero, the instantiation of a pack expansion does not alter the syntactic interpretation of the enclosing construct, even in cases where omitting the pack expansion entirely would otherwise be ill-formed or would result in an ambiguity in the grammar.

10

#

The instantiation of a sizeof... expression ([expr.sizeof]) produces an integral constant with value N.

11

#

When instantiating a pack-index-expression P, let K be the index of P.

The instantiation of P is the id-expression EK.

12

#

When instantiating a pack-index-specifier P, let K be the index of P.

The instantiation of P is the typedef-name EK.

13

#

The instantiation of an alignment-specifier with an ellipsis produces E1 E2 … EN.

14

#

The instantiation of a fold-expression ([expr.prim.fold]) produces:

( ((E1op E2)op ⋯)op EN) for a unary left fold,

( E1 op(⋯ op(EN−1 opEN))) for a unary right fold,

( (((Eop E1)op E2)op ⋯)op EN) for a binary left fold, and

( E1 op(⋯ op(EN−1 op(EN opE)))) for a binary right fold.

In each case,op is the fold-operator.

For a binary fold,E is generated by instantiating the cast-expression that did not contain an unexpanded pack.

[Example 7: 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, the value of the expression is shown in Table 20; if the operator is not listed in Table 20, the instantiation is ill-formed.

Table 20 — Value of folding empty sequences [tab:temp.fold.empty]

🔗
Operator
Value when pack is empty
🔗
&&
true
🔗
🔗
,
void()

15

#

A fold expanded constraint is not instantiated ([temp.constr.fold]).

16

#

The instantiation of any other pack expansion produces a list of elements E1,E2,…,EN.

[Note 1:

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.

[Example 8: 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]