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

371 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[temp.variadic]
# 13 Templates [[temp]](./#temp)
## 13.7 Template declarations [[temp.decls]](temp.decls#temp.variadic)
### 13.7.4 Variadic templates [temp.variadic]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3082)
A [*template parameter pack*](#def:template_parameter_pack "13.7.4Variadic templates[temp.variadic]") is a template parameter
that accepts zero or more template arguments[.](#1.sentence-1)
[*Example [1](#example-1)*: 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*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3096)
A [*function parameter pack*](#def:function_parameter_pack "13.7.4Variadic templates[temp.variadic]") is a function parameter
that accepts zero or more function arguments[.](#2.sentence-1)
[*Example [2](#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](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3109)
An [](#def:init-capture_pack "13.7.4Variadic templates[temp.variadic]")*[*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") pack* is a lambda capture that introduces an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") for each of the elements in the pack expansion of its [*initializer*](dcl.init.general#nt:initializer "9.5.1General[dcl.init.general]")[.](#3.sentence-1)
[*Example [3](#example-3)*: template <typename... Args>void foo(Args... args) {[...xs=args]{ bar(xs...); // xs is an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") pack};} foo(); // xs contains zero [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]")*s* foo(1); // xs contains one [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") — *end example*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3127)
A [*structured binding pack*](#def:structured_binding_pack "13.7.4Variadic templates[temp.variadic]") is an [*sb-identifier*](dcl.pre#nt:sb-identifier "9.1Preamble[dcl.pre]") that introduces zero or more structured bindings ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured binding declarations"))[.](#4.sentence-1)
[*Example [4](#example-4)*: auto foo() -> int(&)[2];
template <class T>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](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3142)
A [*pack*](#def:pack "13.7.4Variadic templates[temp.variadic]") is
a template parameter pack,
a function parameter pack,
an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") pack, or
a structured binding pack[.](#5.sentence-1)
The number of elements of a template parameter pack
or a function parameter pack
is the number of arguments provided for the parameter pack[.](#5.sentence-2)
The number of elements of an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") pack
is the number of elements in the pack expansion of its [*initializer*](dcl.init.general#nt:initializer "9.5.1General[dcl.init.general]")[.](#5.sentence-3)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3154)
A [*pack expansion*](#def:pack_expansion "13.7.4Variadic templates[temp.variadic]") consists of a [*pattern*](#def:pack_expansion,pattern "13.7.4Variadic templates[temp.variadic]") and an ellipsis, the instantiation of which
produces zero or more instantiations of the pattern in a list (described below)[.](#6.sentence-1)
The form of the pattern
depends on the context in which the expansion occurs[.](#6.sentence-2)
Pack
expansions can occur in the following contexts:
- [(6.1)](#6.1)
In a function parameter pack ([[dcl.fct]](dcl.fct "9.3.4.6Functions")); the pattern is the[*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6Functions[dcl.fct]") without the ellipsis[.](#6.1.sentence-1)
- [(6.2)](#6.2)
In a [*using-declaration*](namespace.udecl#nt:using-declaration "9.10The using declaration[namespace.udecl]") ([[namespace.udecl]](namespace.udecl "9.10The using declaration"));
the pattern is a [*using-declarator*](namespace.udecl#nt:using-declarator "9.10The using declaration[namespace.udecl]")[.](#6.2.sentence-1)
- [(6.3)](#6.3)
In a [*friend-type-declaration*](class.mem.general#nt:friend-type-declaration "11.4.1General[class.mem.general]") ([[class.mem.general]](class.mem.general "11.4.1General"));
the pattern is a [*friend-type-specifier*](class.mem.general#nt:friend-type-specifier "11.4.1General[class.mem.general]")[.](#6.3.sentence-1)
- [(6.4)](#6.4)
In a template parameter pack that is a pack expansion ([[temp.param]](temp.param "13.2Template parameters")):
* [(6.4.1)](#6.4.1)
if the template parameter pack is a [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6Functions[dcl.fct]");
the pattern is the [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6Functions[dcl.fct]") without the ellipsis;
* [(6.4.2)](#6.4.2)
if the template parameter pack is a [*type-parameter*](temp.param#nt:type-parameter "13.2Template parameters[temp.param]");
the pattern is the corresponding [*type-parameter*](temp.param#nt:type-parameter "13.2Template parameters[temp.param]") without the ellipsis;
* [(6.4.3)](#6.4.3)
if the template parameter pack is a template template parameter;
the pattern is the corresponding[*type-tt-parameter*](temp.param#nt:type-tt-parameter "13.2Template parameters[temp.param]"),[*variable-tt-parameter*](temp.param#nt:variable-tt-parameter "13.2Template parameters[temp.param]"), or[*concept-tt-parameter*](temp.param#nt:concept-tt-parameter "13.2Template parameters[temp.param]") without the ellipsis[.](#6.4.sentence-1)
- [(6.5)](#6.5)
In an [*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1General[dcl.init.general]") ([[dcl.init]](dcl.init "9.5Initializers"));
the pattern is an [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1General[dcl.init.general]")[.](#6.5.sentence-1)
- [(6.6)](#6.6)
In a [*base-specifier-list*](class.derived.general#nt:base-specifier-list "11.7.1General[class.derived.general]") ([[class.derived]](class.derived "11.7Derived classes"));
the pattern is a [*base-specifier*](class.derived.general#nt:base-specifier "11.7.1General[class.derived.general]")[.](#6.6.sentence-1)
- [(6.7)](#6.7)
In a [*mem-initializer-list*](class.base.init#nt:mem-initializer-list "11.9.3Initializing bases and members[class.base.init]") ([[class.base.init]](class.base.init "11.9.3Initializing bases and members")) for a[*mem-initializer*](class.base.init#nt:mem-initializer "11.9.3Initializing bases and members[class.base.init]") whose [*mem-initializer-id*](class.base.init#nt:mem-initializer-id "11.9.3Initializing bases and members[class.base.init]") denotes a
base class; the pattern is the [*mem-initializer*](class.base.init#nt:mem-initializer "11.9.3Initializing bases and members[class.base.init]")[.](#6.7.sentence-1)
- [(6.8)](#6.8)
In a [*template-argument-list*](temp.names#nt:template-argument-list "13.3Names of template specializations[temp.names]") ([[temp.arg]](temp.arg "13.4Template arguments"));
the pattern is a [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")[.](#6.8.sentence-1)
- [(6.9)](#6.9)
In an [*attribute-list*](dcl.attr.grammar#nt:attribute-list "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") ([[dcl.attr.grammar]](dcl.attr.grammar "9.13.1Attribute syntax and semantics"));
the pattern is an [*attribute*](dcl.attr.grammar#nt:attribute "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")[.](#6.9.sentence-1)
- [(6.10)](#6.10)
In an [*annotation-list*](dcl.attr.grammar#nt:annotation-list "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") ([[dcl.attr.grammar]](dcl.attr.grammar "9.13.1Attribute syntax and semantics"));
the pattern is an [*annotation*](dcl.attr.grammar#nt:annotation "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")[.](#6.10.sentence-1)
- [(6.11)](#6.11)
In an [*alignment-specifier*](dcl.attr.grammar#nt:alignment-specifier "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") ([[dcl.align]](dcl.align "9.13.2Alignment specifier")); the pattern is
the [*alignment-specifier*](dcl.attr.grammar#nt:alignment-specifier "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") without the ellipsis[.](#6.11.sentence-1)
- [(6.12)](#6.12)
In a [*capture-list*](expr.prim.lambda.capture#nt:capture-list "7.5.6.3Captures[expr.prim.lambda.capture]") ([[expr.prim.lambda.capture]](expr.prim.lambda.capture "7.5.6.3Captures")); the pattern is
the [*capture*](expr.prim.lambda.capture#nt:capture "7.5.6.3Captures[expr.prim.lambda.capture]") without the ellipsis[.](#6.12.sentence-1)
- [(6.13)](#6.13)
In a [sizeof... expression](expr.sizeof "7.6.2.5Sizeof[expr.sizeof]"); the pattern is an[*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]")[.](#6.13.sentence-1)
- [(6.14)](#6.14)
In a [*pack-index-expression*](expr.prim.pack.index#nt:pack-index-expression "7.5.5.4Pack indexing expression[expr.prim.pack.index]");
the pattern is an [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]")[.](#6.14.sentence-1)
- [(6.15)](#6.15)
In a [*pack-index-specifier*](dcl.type.pack.index#nt:pack-index-specifier "9.2.9.4Pack indexing specifier[dcl.type.pack.index]");
the pattern is a [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]")[.](#6.15.sentence-1)
- [(6.16)](#6.16)
In a [*fold-expression*](expr.prim.fold#nt:fold-expression "7.5.7Fold expressions[expr.prim.fold]") ([[expr.prim.fold]](expr.prim.fold "7.5.7Fold expressions"));
the pattern is the [*cast-expression*](expr.cast#nt:cast-expression "7.6.3Explicit type conversion (cast notation)[expr.cast]") that contains an unexpanded pack[.](#6.16.sentence-1)
- [(6.17)](#6.17)
In a fold expanded constraint ([[temp.constr.fold]](temp.constr.fold "13.5.2.5Fold expanded constraint"));
the pattern is the constraint of that fold expanded constraint[.](#6.17.sentence-1)
[*Example [5](#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](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3244)
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[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3250)
A pack whose name appears within the pattern of a pack
expansion is expanded by that pack expansion[.](#8.sentence-1)
An appearance of the name of
a pack is only expanded by the innermost enclosing pack expansion[.](#8.sentence-2)
The pattern of a pack expansion shall name one or more packs that
are not expanded by a nested pack expansion; such packs are called[*unexpanded packs*](#def:pack,unexpanded "13.7.4Variadic templates[temp.variadic]") in the pattern[.](#8.sentence-3)
All of the packs expanded
by a pack expansion shall have the same number of arguments specified[.](#8.sentence-4)
An
appearance of a name of a pack that is not expanded is
ill-formed[.](#8.sentence-5)
[*Example [6](#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<short>::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](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3287)
The instantiation of a pack expansion considers
items E1,E2,…,EN,
whereN is the number of elements in the pack expansion parameters[.](#9.sentence-1)
Each Ei is generated by instantiating the pattern and
replacing each pack expansion parameter with its ith element[.](#9.sentence-2)
Such an element, in the context of the instantiation, is interpreted as
follows:
- [(9.1)](#9.1)
if the pack is a template parameter pack, the element is
* [(9.1.1)](#9.1.1)
a [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") for a type template parameter pack,
* [(9.1.2)](#9.1.2)
an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") for a constant template parameter pack, or
* [(9.1.3)](#9.1.3)
a [*template-name*](temp.names#nt:template-name "13.3Names of template specializations[temp.names]") for a template template parameter pack
designating the ith corresponding
type, constant, or template template argument;
- [(9.2)](#9.2)
if the pack is a function parameter pack, the element is an[*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") designating the ith function parameter
that resulted from instantiation of
the function parameter pack declaration;
- [(9.3)](#9.3)
if the pack is an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") pack,
the element is an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") designating the variable introduced by
the ith [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") that resulted from instantiation of
the [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3Captures[expr.prim.lambda.capture]") pack declaration;
otherwise
- [(9.4)](#9.4)
if the pack is a structured binding pack,
the element is an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") 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[.](#9.sentence-4)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3338)
The instantiation of a sizeof... expression ([[expr.sizeof]](expr.sizeof "7.6.2.5Sizeof")) produces
an integral constant with value N[.](#10.sentence-1)
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3342)
When instantiating a [*pack-index-expression*](expr.prim.pack.index#nt:pack-index-expression "7.5.5.4Pack indexing expression[expr.prim.pack.index]") P,
let K be the index of P[.](#11.sentence-1)
The instantiation of P is the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") EK[.](#11.sentence-2)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3347)
When instantiating a [*pack-index-specifier*](dcl.type.pack.index#nt:pack-index-specifier "9.2.9.4Pack indexing specifier[dcl.type.pack.index]") P,
let K be the index of P[.](#12.sentence-1)
The instantiation of P is the [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") EK[.](#12.sentence-2)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3352)
The instantiation of an [*alignment-specifier*](dcl.attr.grammar#nt:alignment-specifier "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") with an ellipsis
produces E1 E2 … EN[.](#13.sentence-1)
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3356)
The instantiation of a [*fold-expression*](expr.prim.fold#nt:fold-expression "7.5.7Fold expressions[expr.prim.fold]") ([[expr.prim.fold]](expr.prim.fold "7.5.7Fold expressions")) produces:
- [(14.1)](#14.1)
( ((E1*op* E2)*op* ⋯)*op* EN) for a unary left fold,
- [(14.2)](#14.2)
( E1 *op*(⋯ *op*(EN−1 *op*EN))) for a unary right fold,
- [(14.3)](#14.3)
( (((E*op* E1)*op* E2)*op* ⋯)*op* EN) for a binary left fold, and
- [(14.4)](#14.4)
( E1 *op*(⋯ *op*(EN−1 *op*(EN *op*E)))) for a binary right fold[.](#14.sentence-1)
In each case,*op* is the [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7Fold expressions[expr.prim.fold]")[.](#14.sentence-2)
For a binary fold,E is generated
by instantiating the [*cast-expression*](expr.cast#nt:cast-expression "7.6.3Explicit type conversion (cast notation)[expr.cast]") that did not contain an unexpanded pack[.](#14.sentence-3)
[*Example [7](#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[.](#14.sentence-4)
— *end example*]
If N is zero for a unary fold,
the value of the expression is shown in Table [20](#tab:temp.fold.empty "Table 20: Value of folding empty sequences");
if the operator is not listed in Table [20](#tab:temp.fold.empty "Table 20: Value of folding empty sequences"),
the instantiation is ill-formed[.](#14.sentence-5)
Table [20](#tab:temp.fold.empty) — Value of folding empty sequences [[tab:temp.fold.empty]](./tab:temp.fold.empty)
| [🔗](#tab:temp.fold.empty-row-1)<br>**Operator** | **Value when pack is empty** |
| --- | --- |
| [🔗](#tab:temp.fold.empty-row-2)<br>&& | true |
| [🔗](#tab:temp.fold.empty-row-3)<br>|| | false |
| [🔗](#tab:temp.fold.empty-row-4)<br>, | void() |
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3430)
A fold expanded constraint is not instantiated ([[temp.constr.fold]](temp.constr.fold "13.5.2.5Fold expanded constraint"))[.](#15.sentence-1)
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3433)
The instantiation of any other pack expansion
produces a list of elements E1,E2,…,EN[.](#16.sentence-1)
[*Note [1](#note-1)*:
The variety of list varies with the context:[*expression-list*](expr.post.general#nt:expression-list "7.6.1.1General[expr.post.general]"),[*base-specifier-list*](class.derived.general#nt:base-specifier-list "11.7.1General[class.derived.general]"),[*template-argument-list*](temp.names#nt:template-argument-list "13.3Names of template specializations[temp.names]"), etc[.](#16.sentence-2)
— *end note*]
When N is zero, the instantiation of the expansion produces an empty list[.](#16.sentence-3)
[*Example [8](#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*]