1904 lines
108 KiB
Markdown
1904 lines
108 KiB
Markdown
[temp.decls]
|
||
|
||
# 13 Templates [[temp]](./#temp)
|
||
|
||
## 13.7 Template declarations [temp.decls]
|
||
|
||
### [13.7.1](#general) General [[temp.decls.general]](temp.decls.general)
|
||
|
||
[1](#general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2592)
|
||
|
||
The template parameters of a template are specified in
|
||
the angle bracket enclosed list
|
||
that immediately follows the keyword template[.](#general-1.sentence-1)
|
||
|
||
[2](#general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2597)
|
||
|
||
A [*primary template*](#def:template,primary "13.7.1 General [temp.decls.general]") declaration is one
|
||
in which the name of the template is not followed by
|
||
a [*template-argument-list*](temp.names#nt:template-argument-list "13.3 Names of template specializations [temp.names]")[.](#general-2.sentence-1)
|
||
|
||
The template argument list of a primary template is
|
||
the template argument list of its [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") ([[temp.arg]](temp.arg "13.4 Template arguments"))[.](#general-2.sentence-2)
|
||
|
||
A template declaration in which the name of the template is followed by
|
||
a [*template-argument-list*](temp.names#nt:template-argument-list "13.3 Names of template specializations [temp.names]") is
|
||
a partial specialization ([[temp.spec.partial]](#temp.spec.partial "13.7.6 Partial specialization")) of
|
||
the template named in the declaration,
|
||
which shall be a class or variable template[.](#general-2.sentence-3)
|
||
|
||
[3](#general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2609)
|
||
|
||
For purposes of name lookup and instantiation,
|
||
default arguments,[*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")*s*,[*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")*s* ([[temp.pre]](temp.pre "13.1 Preamble")),
|
||
and[*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")*s* of function templates
|
||
and
|
||
of member functions of class templates
|
||
are considered definitions;
|
||
each
|
||
default argument,[*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]"),[*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]"),
|
||
or[*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]") is a separate definition
|
||
which is unrelated
|
||
to the templated function definition or
|
||
to any other
|
||
default arguments,[*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")*s*,[*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")*s*,
|
||
or[*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")*s*[.](#general-3.sentence-1)
|
||
|
||
For the purpose of instantiation, the substatements of a[constexpr if](stmt.if#def:constexpr_if "8.5.2 The if statement [stmt.if]") statement are considered definitions[.](#general-3.sentence-2)
|
||
|
||
For the purpose of name lookup and instantiation,
|
||
the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of an [*expansion-statement*](stmt.expand#nt:expansion-statement "8.7 Expansion statements [stmt.expand]") is considered a template definition[.](#general-3.sentence-3)
|
||
|
||
[4](#general-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2641)
|
||
|
||
Because an [*alias-declaration*](dcl.pre#nt:alias-declaration "9.1 Preamble [dcl.pre]") cannot declare a[*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]"), it is not possible to partially or
|
||
explicitly specialize an alias template[.](#general-4.sentence-1)
|
||
|
||
### [13.7.2](#temp.class) Class templates [[temp.class]](temp.class)
|
||
|
||
#### [13.7.2.1](#temp.class.general) General [[temp.class.general]](temp.class.general)
|
||
|
||
[1](#temp.class.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2650)
|
||
|
||
A[*class template*](#def:template,class "13.7.2.1 General [temp.class.general]") defines the layout and operations
|
||
for an unbounded set of related types[.](#temp.class.general-1.sentence-1)
|
||
|
||
[2](#temp.class.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2656)
|
||
|
||
[*Example [1](#temp.class.general-example-1)*:
|
||
|
||
It is possible for a single class templateList to provide an unbounded set of class definitions:
|
||
one class List<T> for every type T,
|
||
each describing a linked list of elements of type T[.](#temp.class.general-2.sentence-1)
|
||
|
||
Similarly, a class template Array describing a contiguous,
|
||
dynamic array can be defined like this:template<class T> class Array { T* v; int sz;public:explicit Array(int);
|
||
T& operator[](int);
|
||
T& elem(int i) { return v[i]; }};
|
||
|
||
The prefix template<class T> specifies that a template is being declared and that a[*type-name*](dcl.type.simple#nt:type-name "9.2.9.3 Simple type specifiers [dcl.type.simple]") T can be used in the declaration[.](#temp.class.general-2.sentence-3)
|
||
|
||
In other words,Array is a parameterized type withT as its parameter[.](#temp.class.general-2.sentence-4)
|
||
|
||
â *end example*]
|
||
|
||
[3](#temp.class.general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2686)
|
||
|
||
[*Note [1](#temp.class.general-note-1)*:
|
||
|
||
When a member of a class
|
||
template is defined outside of the class template definition,
|
||
the member definition is defined as a template definition with the[*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") equivalent to that
|
||
of the class template[.](#temp.class.general-3.sentence-1)
|
||
|
||
The names of the template parameters used in the definition of the member
|
||
can differ from the template parameter names used in the class
|
||
template definition[.](#temp.class.general-3.sentence-2)
|
||
|
||
The class template name in the member definition is followed by
|
||
the template argument list of the [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") ([[temp.arg]](temp.arg "13.4 Template arguments"))[.](#temp.class.general-3.sentence-3)
|
||
|
||
[*Example [2](#temp.class.general-example-2)*: template<class T1, class T2> struct A {void f1(); void f2();};
|
||
|
||
template<class T2, class T1> void A<T2,T1>::f1() { } // OKtemplate<class T2, class T1> void A<T1,T2>::f2() { } // error
|
||
|
||
template<class ... Types> struct B {void f3(); void f4();};
|
||
|
||
template<class ... Types> void B<Types ...>::f3() { } // OKtemplate<class ... Types> void B<Types>::f4() { } // error
|
||
|
||
template<typename T> concept C = true;template<typename T> concept D = true;
|
||
|
||
template<C T> struct S {void f(); void g(); void h(); template<D U> struct Inner;};
|
||
|
||
template<C A> void S<A>::f() { } // OK, [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]")*s* matchtemplate<typename T> void S<T>::g() { } // error: no matching declaration for S<T>template<typename T> requires C<T> // ill-formed, no diagnostic required: [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]")*s* arevoid S<T>::h() { } // functionally equivalent but not equivalenttemplate<C X> template<D Y>struct S<X>::Inner { }; // OK â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
[4](#temp.class.general-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2742)
|
||
|
||
In a partial specialization,
|
||
explicit specialization or
|
||
explicit instantiation of a class template,
|
||
the [*class-key*](class.pre#nt:class-key "11.1 Preamble [class.pre]") shall agree in kind with the original class template declaration ([[dcl.type.elab]](dcl.type.elab "9.2.9.5 Elaborated type specifiers"))[.](#temp.class.general-4.sentence-1)
|
||
|
||
#### [13.7.2.2](#temp.mem.func) Member functions of class templates [[temp.mem.func]](temp.mem.func)
|
||
|
||
[1](#temp.mem.func-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2751)
|
||
|
||
A member function
|
||
of a class template
|
||
may be defined outside of the class
|
||
template definition in which it is declared[.](#temp.mem.func-1.sentence-1)
|
||
|
||
[*Example [1](#temp.mem.func-example-1)*: template<class T> class Array { T* v; int sz;public:explicit Array(int);
|
||
T& operator[](int);
|
||
T& elem(int i) { return v[i]; }};
|
||
|
||
declares three member functions of a class template[.](#temp.mem.func-1.sentence-2)
|
||
|
||
The subscript function can be defined like this:template<class T> T& Array<T>::operator[](int i) {if (i<0 || sz<=i) error("Array: range error"); return v[i];}
|
||
|
||
A constrained member function can be defined out of line:template<typename T> concept C = requires {typename T::type;};
|
||
|
||
template<typename T> struct S {void f() requires C<T>; void g() requires C<T>;};
|
||
|
||
template<typename T>void S<T>::f() requires C<T> { } // OKtemplate<typename T>void S<T>::g() { } // error: no matching function in S<T>
|
||
|
||
â *end example*]
|
||
|
||
[2](#temp.mem.func-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2796)
|
||
|
||
The[*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]")*s* for a member function of a class template are determined by the[*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]")*s* of the type of the object for which the member function is called[.](#temp.mem.func-2.sentence-1)
|
||
|
||
[*Example [2](#temp.mem.func-example-2)*:
|
||
|
||
The[*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]") forArray<T>::operator[] will be determined by theArray to which the subscripting operation is applied[.](#temp.mem.func-2.sentence-2)
|
||
|
||
Array<int> v1(20);
|
||
Array<dcomplex> v2(30);
|
||
|
||
v1[3] = 7; // Array<int>::operator[] v2[3] = dcomplex(7,8); // Array<dcomplex>::operator[] â *end example*]
|
||
|
||
#### [13.7.2.3](#temp.deduct.guide) Deduction guides [[temp.deduct.guide]](temp.deduct.guide)
|
||
|
||
[1](#temp.deduct.guide-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2823)
|
||
|
||
Deduction guides are used
|
||
when a [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") or [*splice-type-specifier*](dcl.type.splice#nt:splice-type-specifier "9.2.9.9 Type splicing [dcl.type.splice]") appears as a type specifier
|
||
for a deduced class type ([[dcl.type.class.deduct]](dcl.type.class.deduct "9.2.9.8 Deduced class template specialization types"))[.](#temp.deduct.guide-1.sentence-1)
|
||
|
||
Deduction guides are not found by name lookup[.](#temp.deduct.guide-1.sentence-2)
|
||
|
||
Instead, when performing class template argument deduction ([[over.match.class.deduct]](over.match.class.deduct "12.2.2.9 Class template argument deduction")),
|
||
all reachable deduction guides declared for the class template are considered[.](#temp.deduct.guide-1.sentence-3)
|
||
|
||
[deduction-guide:](#nt:deduction-guide "13.7.2.3 Deduction guides [temp.deduct.guide]")
|
||
[*explicit-specifier*](dcl.fct.spec#nt:explicit-specifier "9.2.3 Function specifiers [dcl.fct.spec]")opt [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") ( [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") ) -> [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")opt ;
|
||
|
||
[2](#temp.deduct.guide-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2837)
|
||
|
||
[*Example [1](#temp.deduct.guide-example-1)*: template<class T, class D = int>struct S { T data;};template<class U> S(U) -> S<typename U::type>;
|
||
|
||
struct A {using type = short; operator type();};
|
||
S x{A()}; // x is of type S<short, int> â *end example*]
|
||
|
||
[3](#temp.deduct.guide-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2855)
|
||
|
||
The same restrictions apply
|
||
to the [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of a deduction guide
|
||
as in a function declaration ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")),
|
||
except that a generic parameter type placeholder ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers"))
|
||
shall not appear in the [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of
|
||
a deduction guide[.](#temp.deduct.guide-3.sentence-1)
|
||
|
||
The [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") shall name a class template specialization[.](#temp.deduct.guide-3.sentence-2)
|
||
|
||
The [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") shall be the same [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") as the [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") of the [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")[.](#temp.deduct.guide-3.sentence-3)
|
||
|
||
A [*deduction-guide*](#nt:deduction-guide "13.7.2.3 Deduction guides [temp.deduct.guide]") shall inhabit the scope
|
||
to which the corresponding class template belongs
|
||
and, for a member class template, have the same access[.](#temp.deduct.guide-3.sentence-4)
|
||
|
||
Two deduction guide declarations
|
||
for the same class template
|
||
shall not have equivalent [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]")*s* if either is reachable from the other[.](#temp.deduct.guide-3.sentence-5)
|
||
|
||
#### [13.7.2.4](#temp.mem.class) Member classes of class templates [[temp.mem.class]](temp.mem.class)
|
||
|
||
[1](#temp.mem.class-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2880)
|
||
|
||
A member class of a class template may be defined outside the class template
|
||
definition in which it is declared[.](#temp.mem.class-1.sentence-1)
|
||
|
||
[*Note [1](#temp.mem.class-note-1)*:
|
||
|
||
The member class must be defined before its first use that requires
|
||
an instantiation ([[temp.inst]](temp.inst "13.9.2 Implicit instantiation"))[.](#temp.mem.class-1.sentence-2)
|
||
|
||
For example,template<class T> struct A {class B;};
|
||
A<int>::B* b1; // OK, requires A to be defined but not A::Btemplate<class T> class A<T>::B { };
|
||
A<int>::B b2; // OK, requires A::B to be defined
|
||
|
||
â *end note*]
|
||
|
||
#### [13.7.2.5](#temp.static) Static data members of class templates [[temp.static]](temp.static)
|
||
|
||
[1](#temp.static-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2899)
|
||
|
||
A definition for a static data member or static data member template may be
|
||
provided in a namespace scope enclosing the definition of the static member's
|
||
class template[.](#temp.static-1.sentence-1)
|
||
|
||
[*Example [1](#temp.static-example-1)*: template<class T> class X {static T s;};template<class T> T X<T>::s = 0;
|
||
|
||
struct limits {template<class T>static const T min; // declaration};
|
||
|
||
template<class T>const T limits::min = { }; // definition â *end example*]
|
||
|
||
[2](#temp.static-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2921)
|
||
|
||
An explicit specialization of a static data member declared as an array of unknown
|
||
bound can have a different bound from its definition, if any[.](#temp.static-2.sentence-1)
|
||
|
||
[*Example [2](#temp.static-example-2)*: template <class T> struct A {static int i[];};template <class T> int A<T>::i[4]; // 4 elementstemplate <> int A<int>::i[] = { 1 }; // OK, 1 element â *end example*]
|
||
|
||
#### [13.7.2.6](#temp.mem.enum) Enumeration members of class templates [[temp.mem.enum]](temp.mem.enum)
|
||
|
||
[1](#temp.mem.enum-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2936)
|
||
|
||
An enumeration member of a class template may be defined outside the class
|
||
template definition[.](#temp.mem.enum-1.sentence-1)
|
||
|
||
[*Example [1](#temp.mem.enum-example-1)*: template<class T> struct A {enum E : T;};template<class T> enum A<T>::E : T { e1, e2 };
|
||
A<int>::E e = A<int>::e1; â *end example*]
|
||
|
||
### [13.7.3](#temp.mem) Member templates [[temp.mem]](temp.mem)
|
||
|
||
[1](#temp.mem-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2951)
|
||
|
||
A template can be declared within a class or class template; such a template
|
||
is called a member template[.](#temp.mem-1.sentence-1)
|
||
|
||
A member template can be defined within or outside its class definition or
|
||
class template definition[.](#temp.mem-1.sentence-2)
|
||
|
||
A member template of a class template that is defined outside of its class
|
||
template definition shall be specified with
|
||
a [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") equivalent to that
|
||
of the class template followed by
|
||
a [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") equivalent to that
|
||
of the member template ([[temp.over.link]](#temp.over.link "13.7.7.2 Function template overloading"))[.](#temp.mem-1.sentence-3)
|
||
|
||
[*Example [1](#temp.mem-example-1)*: template<class T> struct string {template<class T2> int compare(const T2&); template<class T2> string(const string<T2>& s) { /* ... */ }};
|
||
|
||
template<class T> template<class T2> int string<T>::compare(const T2& s) {} â *end example*]
|
||
|
||
[*Example [2](#temp.mem-example-2)*: template<typename T> concept C1 = true;template<typename T> concept C2 = sizeof(T) <= 4;
|
||
|
||
template<C1 T> struct S {template<C2 U> void f(U); template<C2 U> void g(U);};
|
||
|
||
template<C1 T> template<C2 U>void S<T>::f(U) { } // OKtemplate<C1 T> template<typename U>void S<T>::g(U) { } // error: no matching function in S<T> â *end example*]
|
||
|
||
[2](#temp.mem-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2990)
|
||
|
||
A local class of non-closure type shall not have member templates[.](#temp.mem-2.sentence-1)
|
||
|
||
[Access control rules](class.access "11.8 Member access control [class.access]") apply to member template names[.](#temp.mem-2.sentence-2)
|
||
|
||
A destructor shall not be a member
|
||
template[.](#temp.mem-2.sentence-3)
|
||
|
||
A non-template member function ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) with a given name
|
||
and type and a member function template of the same name, which could be
|
||
used to generate a specialization of the same type, can both be
|
||
declared in a class[.](#temp.mem-2.sentence-4)
|
||
|
||
When both exist, a use of that name and type refers to the
|
||
non-template member unless an explicit template argument list is supplied[.](#temp.mem-2.sentence-5)
|
||
|
||
[*Example [3](#temp.mem-example-3)*: template <class T> struct A {void f(int); template <class T2> void f(T2);};
|
||
|
||
template <> void A<int>::f(int) { } // non-template member functiontemplate <> template <> void A<int>::f<>(int) { } // member function template specializationint main() { A<char> ac;
|
||
ac.f(1); // non-template ac.f('c'); // template ac.f<>(1); // template} â *end example*]
|
||
|
||
[3](#temp.mem-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3021)
|
||
|
||
A member function template shall not be declared virtual[.](#temp.mem-3.sentence-1)
|
||
|
||
[*Example [4](#temp.mem-example-4)*: template <class T> struct AA {template <class C> virtual void g(C); // errorvirtual void f(); // OK}; â *end example*]
|
||
|
||
[4](#temp.mem-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3032)
|
||
|
||
A specialization of
|
||
a member function template does not override a virtual function from a
|
||
base class[.](#temp.mem-4.sentence-1)
|
||
|
||
[*Example [5](#temp.mem-example-5)*: class B {virtual void f(int);};
|
||
|
||
class D : public B {template <class T> void f(T); // does not override B::f(int)void f(int i) { f<>(i); } // overriding function that calls the function template specialization}; â *end example*]
|
||
|
||
[5](#temp.mem-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3049)
|
||
|
||
[*Note [1](#temp.mem-note-1)*:
|
||
|
||
A specialization of a
|
||
conversion function template
|
||
is named in
|
||
the same way as a non-template conversion function that converts to
|
||
the same type ([[class.conv.fct]](class.conv.fct "11.4.8.3 Conversion functions"))[.](#temp.mem-5.sentence-1)
|
||
|
||
[*Example [6](#temp.mem-example-6)*: struct A {template <class T> operator T*();};template <class T> A::operator T*() { return 0; }template <> A::operator char*() { return 0; } // specializationtemplate A::operator void*(); // explicit instantiationint main() { A a; int* ip;
|
||
ip = a.operator int*(); // explicit call to template operator A::operator int*()} â *end example*]
|
||
|
||
An expression designating
|
||
a particular specialization of a conversion function template
|
||
can only be formed with a [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9 Expression splicing [expr.prim.splice]")[.](#temp.mem-5.sentence-2)
|
||
|
||
There is no analogous syntax to form a [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") ([[temp.names]](temp.names "13.3 Names of template specializations"))
|
||
for such a function
|
||
by providing an explicit template argument list ([[temp.arg.explicit]](temp.arg.explicit "13.10.2 Explicit template argument specification"))[.](#temp.mem-5.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
### [13.7.4](#temp.variadic) Variadic templates [[temp.variadic]](temp.variadic)
|
||
|
||
[1](#temp.variadic-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3082)
|
||
|
||
A [*template parameter pack*](#def:template_parameter_pack "13.7.4 Variadic templates [temp.variadic]") is a template parameter
|
||
that accepts zero or more template arguments[.](#temp.variadic-1.sentence-1)
|
||
|
||
[*Example [1](#temp.variadic-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](#temp.variadic-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3096)
|
||
|
||
A [*function parameter pack*](#def:function_parameter_pack "13.7.4 Variadic templates [temp.variadic]") is a function parameter
|
||
that accepts zero or more function arguments[.](#temp.variadic-2.sentence-1)
|
||
|
||
[*Example [2](#temp.variadic-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](#temp.variadic-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3109)
|
||
|
||
An [](#def:init-capture_pack "13.7.4 Variadic templates [temp.variadic]")*[*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") pack* is a lambda capture that introduces an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") for each of the elements in the pack expansion of its [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")[.](#temp.variadic-3.sentence-1)
|
||
|
||
[*Example [3](#temp.variadic-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.3 Captures [expr.prim.lambda.capture]") pack};} foo(); // xs contains zero [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]")*s* foo(1); // xs contains one [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") â *end example*]
|
||
|
||
[4](#temp.variadic-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3127)
|
||
|
||
A [*structured binding pack*](#def:structured_binding_pack "13.7.4 Variadic templates [temp.variadic]") is an [*sb-identifier*](dcl.pre#nt:sb-identifier "9.1 Preamble [dcl.pre]") that introduces zero or more structured bindings ([[dcl.struct.bind]](dcl.struct.bind "9.7 Structured binding declarations"))[.](#temp.variadic-4.sentence-1)
|
||
|
||
[*Example [4](#temp.variadic-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](#temp.variadic-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3142)
|
||
|
||
A [*pack*](#def:pack "13.7.4 Variadic 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.3 Captures [expr.prim.lambda.capture]") pack, or
|
||
a structured binding pack[.](#temp.variadic-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[.](#temp.variadic-5.sentence-2)
|
||
|
||
The number of elements of an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") pack
|
||
is the number of elements in the pack expansion of its [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")[.](#temp.variadic-5.sentence-3)
|
||
|
||
[6](#temp.variadic-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3154)
|
||
|
||
A [*pack expansion*](#def:pack_expansion "13.7.4 Variadic templates [temp.variadic]") consists of a [*pattern*](#def:pack_expansion,pattern "13.7.4 Variadic templates [temp.variadic]") and an ellipsis, the instantiation of which
|
||
produces zero or more instantiations of the pattern in a list (described below)[.](#temp.variadic-6.sentence-1)
|
||
|
||
The form of the pattern
|
||
depends on the context in which the expansion occurs[.](#temp.variadic-6.sentence-2)
|
||
|
||
Pack
|
||
expansions can occur in the following contexts:
|
||
|
||
- [(6.1)](#temp.variadic-6.1)
|
||
|
||
In a function parameter pack ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")); the pattern is the[*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") without the ellipsis[.](#temp.variadic-6.1.sentence-1)
|
||
|
||
- [(6.2)](#temp.variadic-6.2)
|
||
|
||
In a [*using-declaration*](namespace.udecl#nt:using-declaration "9.10 The using declaration [namespace.udecl]") ([[namespace.udecl]](namespace.udecl "9.10 The using declaration"));
|
||
the pattern is a [*using-declarator*](namespace.udecl#nt:using-declarator "9.10 The using declaration [namespace.udecl]")[.](#temp.variadic-6.2.sentence-1)
|
||
|
||
- [(6.3)](#temp.variadic-6.3)
|
||
|
||
In a [*friend-type-declaration*](class.mem.general#nt:friend-type-declaration "11.4.1 General [class.mem.general]") ([[class.mem.general]](class.mem.general "11.4.1 General"));
|
||
the pattern is a [*friend-type-specifier*](class.mem.general#nt:friend-type-specifier "11.4.1 General [class.mem.general]")[.](#temp.variadic-6.3.sentence-1)
|
||
|
||
- [(6.4)](#temp.variadic-6.4)
|
||
|
||
In a template parameter pack that is a pack expansion ([[temp.param]](temp.param "13.2 Template parameters")):
|
||
* [(6.4.1)](#temp.variadic-6.4.1)
|
||
|
||
if the template parameter pack is a [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]");
|
||
the pattern is the [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]") without the ellipsis;
|
||
|
||
* [(6.4.2)](#temp.variadic-6.4.2)
|
||
|
||
if the template parameter pack is a [*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]");
|
||
the pattern is the corresponding [*type-parameter*](temp.param#nt:type-parameter "13.2 Template parameters [temp.param]") without the ellipsis;
|
||
|
||
* [(6.4.3)](#temp.variadic-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.2 Template parameters [temp.param]"),[*variable-tt-parameter*](temp.param#nt:variable-tt-parameter "13.2 Template parameters [temp.param]"), or[*concept-tt-parameter*](temp.param#nt:concept-tt-parameter "13.2 Template parameters [temp.param]") without the ellipsis[.](#temp.variadic-6.4.sentence-1)
|
||
|
||
- [(6.5)](#temp.variadic-6.5)
|
||
|
||
In an [*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1 General [dcl.init.general]") ([[dcl.init]](dcl.init "9.5 Initializers"));
|
||
the pattern is an [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [dcl.init.general]")[.](#temp.variadic-6.5.sentence-1)
|
||
|
||
- [(6.6)](#temp.variadic-6.6)
|
||
|
||
In a [*base-specifier-list*](class.derived.general#nt:base-specifier-list "11.7.1 General [class.derived.general]") ([[class.derived]](class.derived "11.7 Derived classes"));
|
||
the pattern is a [*base-specifier*](class.derived.general#nt:base-specifier "11.7.1 General [class.derived.general]")[.](#temp.variadic-6.6.sentence-1)
|
||
|
||
- [(6.7)](#temp.variadic-6.7)
|
||
|
||
In a [*mem-initializer-list*](class.base.init#nt:mem-initializer-list "11.9.3 Initializing bases and members [class.base.init]") ([[class.base.init]](class.base.init "11.9.3 Initializing bases and members")) for a[*mem-initializer*](class.base.init#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") whose [*mem-initializer-id*](class.base.init#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") denotes a
|
||
base class; the pattern is the [*mem-initializer*](class.base.init#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]")[.](#temp.variadic-6.7.sentence-1)
|
||
|
||
- [(6.8)](#temp.variadic-6.8)
|
||
|
||
In a [*template-argument-list*](temp.names#nt:template-argument-list "13.3 Names of template specializations [temp.names]") ([[temp.arg]](temp.arg "13.4 Template arguments"));
|
||
the pattern is a [*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]")[.](#temp.variadic-6.8.sentence-1)
|
||
|
||
- [(6.9)](#temp.variadic-6.9)
|
||
|
||
In an [*attribute-list*](dcl.attr.grammar#nt:attribute-list "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") ([[dcl.attr.grammar]](dcl.attr.grammar "9.13.1 Attribute syntax and semantics"));
|
||
the pattern is an [*attribute*](dcl.attr.grammar#nt:attribute "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")[.](#temp.variadic-6.9.sentence-1)
|
||
|
||
- [(6.10)](#temp.variadic-6.10)
|
||
|
||
In an [*annotation-list*](dcl.attr.grammar#nt:annotation-list "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") ([[dcl.attr.grammar]](dcl.attr.grammar "9.13.1 Attribute syntax and semantics"));
|
||
the pattern is an [*annotation*](dcl.attr.grammar#nt:annotation "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")[.](#temp.variadic-6.10.sentence-1)
|
||
|
||
- [(6.11)](#temp.variadic-6.11)
|
||
|
||
In an [*alignment-specifier*](dcl.attr.grammar#nt:alignment-specifier "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") ([[dcl.align]](dcl.align "9.13.2 Alignment specifier")); the pattern is
|
||
the [*alignment-specifier*](dcl.attr.grammar#nt:alignment-specifier "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") without the ellipsis[.](#temp.variadic-6.11.sentence-1)
|
||
|
||
- [(6.12)](#temp.variadic-6.12)
|
||
|
||
In a [*capture-list*](expr.prim.lambda.capture#nt:capture-list "7.5.6.3 Captures [expr.prim.lambda.capture]") ([[expr.prim.lambda.capture]](expr.prim.lambda.capture "7.5.6.3 Captures")); the pattern is
|
||
the [*capture*](expr.prim.lambda.capture#nt:capture "7.5.6.3 Captures [expr.prim.lambda.capture]") without the ellipsis[.](#temp.variadic-6.12.sentence-1)
|
||
|
||
- [(6.13)](#temp.variadic-6.13)
|
||
|
||
In a [sizeof... expression](expr.sizeof "7.6.2.5 Sizeof [expr.sizeof]"); the pattern is an[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")[.](#temp.variadic-6.13.sentence-1)
|
||
|
||
- [(6.14)](#temp.variadic-6.14)
|
||
|
||
In a [*pack-index-expression*](expr.prim.pack.index#nt:pack-index-expression "7.5.5.4 Pack indexing expression [expr.prim.pack.index]");
|
||
the pattern is an [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")[.](#temp.variadic-6.14.sentence-1)
|
||
|
||
- [(6.15)](#temp.variadic-6.15)
|
||
|
||
In a [*pack-index-specifier*](dcl.type.pack.index#nt:pack-index-specifier "9.2.9.4 Pack indexing specifier [dcl.type.pack.index]");
|
||
the pattern is a [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]")[.](#temp.variadic-6.15.sentence-1)
|
||
|
||
- [(6.16)](#temp.variadic-6.16)
|
||
|
||
In a [*fold-expression*](expr.prim.fold#nt:fold-expression "7.5.7 Fold expressions [expr.prim.fold]") ([[expr.prim.fold]](expr.prim.fold "7.5.7 Fold expressions"));
|
||
the pattern is the [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]") that contains an unexpanded pack[.](#temp.variadic-6.16.sentence-1)
|
||
|
||
- [(6.17)](#temp.variadic-6.17)
|
||
|
||
In a fold expanded constraint ([[temp.constr.fold]](temp.constr.fold "13.5.2.5 Fold expanded constraint"));
|
||
the pattern is the constraint of that fold expanded constraint[.](#temp.variadic-6.17.sentence-1)
|
||
|
||
[*Example [5](#temp.variadic-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](#temp.variadic-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[.](#temp.variadic-7.sentence-1)
|
||
|
||
[8](#temp.variadic-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[.](#temp.variadic-8.sentence-1)
|
||
|
||
An appearance of the name of
|
||
a pack is only expanded by the innermost enclosing pack expansion[.](#temp.variadic-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.4 Variadic templates [temp.variadic]") in the pattern[.](#temp.variadic-8.sentence-3)
|
||
|
||
All of the packs expanded
|
||
by a pack expansion shall have the same number of arguments specified[.](#temp.variadic-8.sentence-4)
|
||
|
||
An
|
||
appearance of a name of a pack that is not expanded is
|
||
ill-formed[.](#temp.variadic-8.sentence-5)
|
||
|
||
[*Example [6](#temp.variadic-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](#temp.variadic-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[.](#temp.variadic-9.sentence-1)
|
||
|
||
Each Ei is generated by instantiating the pattern and
|
||
replacing each pack expansion parameter with its ith element[.](#temp.variadic-9.sentence-2)
|
||
|
||
Such an element, in the context of the instantiation, is interpreted as
|
||
follows:
|
||
|
||
- [(9.1)](#temp.variadic-9.1)
|
||
|
||
if the pack is a template parameter pack, the element is
|
||
* [(9.1.1)](#temp.variadic-9.1.1)
|
||
|
||
a [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") for a type template parameter pack,
|
||
|
||
* [(9.1.2)](#temp.variadic-9.1.2)
|
||
|
||
an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") for a constant template parameter pack, or
|
||
|
||
* [(9.1.3)](#temp.variadic-9.1.3)
|
||
|
||
a [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") for a template template parameter pack
|
||
|
||
designating the ith corresponding
|
||
type, constant, or template template argument;
|
||
|
||
- [(9.2)](#temp.variadic-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.1 General [expr.prim.id.general]") designating the ith function parameter
|
||
that resulted from instantiation of
|
||
the function parameter pack declaration;
|
||
|
||
- [(9.3)](#temp.variadic-9.3)
|
||
|
||
if the pack is an [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") pack,
|
||
the element is an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") designating the variable introduced by
|
||
the ith [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") that resulted from instantiation of
|
||
the [*init-capture*](expr.prim.lambda.capture#nt:init-capture "7.5.6.3 Captures [expr.prim.lambda.capture]") pack declaration;
|
||
otherwise
|
||
|
||
- [(9.4)](#temp.variadic-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.1 General [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[.](#temp.variadic-9.sentence-4)
|
||
|
||
[10](#temp.variadic-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.5 Sizeof")) produces
|
||
an integral constant with value N[.](#temp.variadic-10.sentence-1)
|
||
|
||
[11](#temp.variadic-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.4 Pack indexing expression [expr.prim.pack.index]") P,
|
||
let K be the index of P[.](#temp.variadic-11.sentence-1)
|
||
|
||
The instantiation of P is the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") EK[.](#temp.variadic-11.sentence-2)
|
||
|
||
[12](#temp.variadic-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.4 Pack indexing specifier [dcl.type.pack.index]") P,
|
||
let K be the index of P[.](#temp.variadic-12.sentence-1)
|
||
|
||
The instantiation of P is the [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") EK[.](#temp.variadic-12.sentence-2)
|
||
|
||
[13](#temp.variadic-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.1 Attribute syntax and semantics [dcl.attr.grammar]") with an ellipsis
|
||
produces E1 E2 … EN[.](#temp.variadic-13.sentence-1)
|
||
|
||
[14](#temp.variadic-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.7 Fold expressions [expr.prim.fold]") ([[expr.prim.fold]](expr.prim.fold "7.5.7 Fold expressions")) produces:
|
||
|
||
- [(14.1)](#temp.variadic-14.1)
|
||
|
||
( ((E1*op* E2)*op* â¯)*op* EN) for a unary left fold,
|
||
|
||
- [(14.2)](#temp.variadic-14.2)
|
||
|
||
( E1 *op*(⯠*op*(ENâ1 *op*EN))) for a unary right fold,
|
||
|
||
- [(14.3)](#temp.variadic-14.3)
|
||
|
||
( (((E*op* E1)*op* E2)*op* â¯)*op* EN) for a binary left fold, and
|
||
|
||
- [(14.4)](#temp.variadic-14.4)
|
||
|
||
( E1 *op*(⯠*op*(ENâ1 *op*(EN *op*E)))) for a binary right fold[.](#temp.variadic-14.sentence-1)
|
||
|
||
In each case,*op* is the [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]")[.](#temp.variadic-14.sentence-2)
|
||
|
||
For a binary fold,E is generated
|
||
by instantiating the [*cast-expression*](expr.cast#nt:cast-expression "7.6.3 Explicit type conversion (cast notation) [expr.cast]") that did not contain an unexpanded pack[.](#temp.variadic-14.sentence-3)
|
||
|
||
[*Example [7](#temp.variadic-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[.](#temp.variadic-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[.](#temp.variadic-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](#temp.variadic-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.5 Fold expanded constraint"))[.](#temp.variadic-15.sentence-1)
|
||
|
||
[16](#temp.variadic-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[.](#temp.variadic-16.sentence-1)
|
||
|
||
[*Note [1](#temp.variadic-note-1)*:
|
||
|
||
The variety of list varies with the context:[*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]"),[*base-specifier-list*](class.derived.general#nt:base-specifier-list "11.7.1 General [class.derived.general]"),[*template-argument-list*](temp.names#nt:template-argument-list "13.3 Names of template specializations [temp.names]"), etc[.](#temp.variadic-16.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
When N is zero, the instantiation of the expansion produces an empty list[.](#temp.variadic-16.sentence-3)
|
||
|
||
[*Example [8](#temp.variadic-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*]
|
||
|
||
### [13.7.5](#temp.friend) Friends [[temp.friend]](temp.friend)
|
||
|
||
[1](#temp.friend-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3457)
|
||
|
||
A friend of a class or class template can be a function template or
|
||
class template, a specialization of a function template or class
|
||
template, or a non-template function or class[.](#temp.friend-1.sentence-1)
|
||
|
||
[*Example [1](#temp.friend-example-1)*: template<class T> class task;template<class T> task<T>* preempt(task<T>*);
|
||
|
||
template<class T> class task {friend void next_time(); friend void process(task<T>*); friend task<T>* preempt<T>(task<T>*); template<class C> friend int func(C); friend class task<int>; template<class P> friend class frd;};
|
||
|
||
Here,
|
||
each specialization of thetask class template has the functionnext_time as a friend;
|
||
becauseprocess does not have explicit[*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]")*s*,
|
||
each specialization of thetask class template has an appropriately typed functionprocess as a friend, and this friend is not a function template specialization;
|
||
because the friendpreempt has an explicit[*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]")T,
|
||
each specialization of thetask class template has the appropriate specialization of the function
|
||
templatepreempt as a friend;
|
||
and each specialization of thetask class template has all specializations of the function templatefunc as friends[.](#temp.friend-1.sentence-2)
|
||
|
||
Similarly,
|
||
each specialization of thetask class template has the class template specializationtask<int> as a friend, and has all specializations of the class templatefrd as friends[.](#temp.friend-1.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[2](#temp.friend-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3519)
|
||
|
||
Friend classes, class templates, functions, or function templates
|
||
can be declared within a class template[.](#temp.friend-2.sentence-1)
|
||
|
||
When a template is instantiated,
|
||
its friend declarations are found by name lookup
|
||
as if the specialization had been explicitly declared at
|
||
its point of instantiation[.](#temp.friend-2.sentence-2)
|
||
|
||
[*Note [1](#temp.friend-note-1)*:
|
||
|
||
They can introduce entities
|
||
that belong to an enclosing namespace scope ([[dcl.meaning]](dcl.meaning "9.3.4 Meaning of declarators")),
|
||
in which case they are attached to
|
||
the same module as the class template ([[module.unit]](module.unit "10.1 Module units and purviews"))[.](#temp.friend-2.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[3](#temp.friend-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3533)
|
||
|
||
A friend template may be declared within a class or class template[.](#temp.friend-3.sentence-1)
|
||
|
||
A friend function template may be defined within a class or class
|
||
template, but a friend class template may not be defined in a class
|
||
or class template[.](#temp.friend-3.sentence-2)
|
||
|
||
In these cases, all specializations of the friend class or friend function
|
||
template are friends of the class or class template granting friendship[.](#temp.friend-3.sentence-3)
|
||
|
||
[*Example [2](#temp.friend-example-2)*: class A {template<class T> friend class B; // OKtemplate<class T> friend void f(T) { /* ... */ } // OK}; â *end example*]
|
||
|
||
[4](#temp.friend-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3549)
|
||
|
||
A template friend declaration specifies that all specializations of that
|
||
template, whether they are implicitly instantiated ([[temp.inst]](temp.inst "13.9.2 Implicit instantiation")), partially
|
||
specialized ([[temp.spec.partial]](#temp.spec.partial "13.7.6 Partial specialization")) or explicitly specialized ([[temp.expl.spec]](temp.expl.spec "13.9.4 Explicit specialization")),
|
||
are friends of the class containing the template friend declaration[.](#temp.friend-4.sentence-1)
|
||
|
||
[*Example [3](#temp.friend-example-3)*: class X {template<class T> friend struct A; class Y { };};
|
||
|
||
template<class T> struct A { X::Y ab; }; // OKtemplate<class T> struct A<T*> { X::Y ab; }; // OK â *end example*]
|
||
|
||
[5](#temp.friend-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3566)
|
||
|
||
A template friend declaration may declare
|
||
a member of a dependent type to be a friend[.](#temp.friend-5.sentence-1)
|
||
|
||
The friend declaration shall declare a function or
|
||
specify a type with an [*elaborated-type-specifier*](dcl.type.elab#nt:elaborated-type-specifier "9.2.9.5 Elaborated type specifiers [dcl.type.elab]"),
|
||
in either case with a [*nested-name-specifier*](expr.prim.id.qual#nt:nested-name-specifier "7.5.5.3 Qualified names [expr.prim.id.qual]") ending with a [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]"), *C*,
|
||
whose [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]") names a class template[.](#temp.friend-5.sentence-2)
|
||
|
||
The template parameters of the template friend declaration
|
||
shall be deducible from *C* ([[temp.deduct.type]](temp.deduct.type "13.10.3.6 Deducing template arguments from a type"))[.](#temp.friend-5.sentence-3)
|
||
|
||
In this case,
|
||
a member of a specialization *S* of the class template
|
||
is a friend of the class granting friendship
|
||
if deduction of the template parameters
|
||
of *C* from *S* succeeds, and
|
||
substituting the deduced template arguments into the friend declaration
|
||
produces a declaration that corresponds to
|
||
the member of the specialization[.](#temp.friend-5.sentence-4)
|
||
|
||
[*Example [4](#temp.friend-example-4)*: template<class T> struct A {struct B { }; void f(); struct D {void g(); };
|
||
T h(); template<T U> T i();};template<> struct A<int> {struct B { }; int f(); struct D {void g(); }; template<int U> int i();};template<> struct A<float*> {int *h();};
|
||
|
||
class C {template<class T> friend struct A<T>::B; // grants friendship to A<int>::B even though// it is not a specialization of A<T>::Btemplate<class T> friend void A<T>::f(); // does not grant friendship to A<int>::f()// because its return type does not matchtemplate<class T> friend void A<T>::D::g(); // error: A<T>::D does not end with a [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]")template<class T> friend int *A<T*>::h(); // grants friendship to A<int*>::h() and A<float*>::h()template<class T> template<T U> // grants friendship to instantiations of A<T>::i() andfriend T A<T>::i(); // to A<int>::i(), and thereby to all specializations}; // of those function templates â *end example*]
|
||
|
||
[6](#temp.friend-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3620)
|
||
|
||
A friend template shall not be declared in a local class[.](#temp.friend-6.sentence-1)
|
||
|
||
[7](#temp.friend-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3623)
|
||
|
||
Friend declarations shall not declare partial specializations[.](#temp.friend-7.sentence-1)
|
||
|
||
[*Example [5](#temp.friend-example-5)*: template<class T> class A { };class X {template<class T> friend class A<T*>; // error}; â *end example*]
|
||
|
||
[8](#temp.friend-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3634)
|
||
|
||
When a friend declaration refers to a specialization of a function
|
||
template, the function parameter declarations shall not include
|
||
default arguments, nor shall
|
||
the inline, constexpr, or consteval specifiers
|
||
be used in such a declaration[.](#temp.friend-8.sentence-1)
|
||
|
||
[9](#temp.friend-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3641)
|
||
|
||
A non-template friend declaration
|
||
with a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") shall be a definition[.](#temp.friend-9.sentence-1)
|
||
|
||
A friend function template
|
||
with a constraint that depends on a template parameter from an enclosing template
|
||
shall be a definition[.](#temp.friend-9.sentence-2)
|
||
|
||
Such a constrained friend function or function template declaration
|
||
does not declare the same function or function template as a declaration in any other scope[.](#temp.friend-9.sentence-3)
|
||
|
||
### [13.7.6](#temp.spec.partial) Partial specialization [[temp.spec.partial]](temp.spec.partial)
|
||
|
||
#### [13.7.6.1](#temp.spec.partial.general) General [[temp.spec.partial.general]](temp.spec.partial.general)
|
||
|
||
[1](#temp.spec.partial.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3655)
|
||
|
||
A partial specialization of a template provides an alternative definition
|
||
of the template that is used instead of the primary definition when the
|
||
arguments in a specialization match those given in the partial
|
||
specialization ([[temp.spec.partial.match]](#temp.spec.partial.match "13.7.6.2 Matching of partial specializations"))[.](#temp.spec.partial.general-1.sentence-1)
|
||
|
||
A declaration of the primary template shall precede
|
||
any partial specialization of
|
||
that template[.](#temp.spec.partial.general-1.sentence-2)
|
||
|
||
A partial specialization shall be reachable from any use of a template
|
||
specialization that would make use of the partial specialization as the result of
|
||
an implicit or explicit instantiation; no diagnostic is required[.](#temp.spec.partial.general-1.sentence-3)
|
||
|
||
[2](#temp.spec.partial.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3668)
|
||
|
||
Two partial specialization declarations declare the same entity
|
||
if they are partial specializations of the same template and have equivalent[*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]")*s* and template argument lists ([[temp.over.link]](#temp.over.link "13.7.7.2 Function template overloading"))[.](#temp.spec.partial.general-2.sentence-1)
|
||
|
||
Each partial specialization is a distinct template[.](#temp.spec.partial.general-2.sentence-2)
|
||
|
||
[3](#temp.spec.partial.general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3674)
|
||
|
||
[*Example [1](#temp.spec.partial.general-example-1)*: template<class T1, class T2, int I> class A { };template<class T, int I> class A<T, T*, I> { };template<class T1, class T2, int I> class A<T1*, T2, I> { };template<class T> class A<int, T*, 5> { };template<class T1, class T2, int I> class A<T1, T2*, I> { };
|
||
|
||
The first declaration declares the primary (unspecialized) class template[.](#temp.spec.partial.general-3.sentence-1)
|
||
|
||
The second and subsequent declarations declare partial specializations of
|
||
the primary template[.](#temp.spec.partial.general-3.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[4](#temp.spec.partial.general-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3689)
|
||
|
||
A partial specialization may be constrained ([[temp.constr]](temp.constr "13.5 Template constraints"))[.](#temp.spec.partial.general-4.sentence-1)
|
||
|
||
[*Example [2](#temp.spec.partial.general-example-2)*: template<typename T> concept C = true;
|
||
|
||
template<typename T> struct X { };template<typename T> struct X<T*> { }; // #1template<C T> struct X<T> { }; // #2
|
||
|
||
Both partial specializations are more specialized than the primary template[.](#temp.spec.partial.general-4.sentence-2)
|
||
|
||
#1 is more specialized because the deduction of its template arguments
|
||
from the template argument list of the class template specialization succeeds,
|
||
while the reverse does not[.](#temp.spec.partial.general-4.sentence-3)
|
||
|
||
#2 is more specialized because the template arguments are equivalent,
|
||
but the partial specialization is more constrained ([[temp.constr.order]](temp.constr.order "13.5.5 Partial ordering by constraints"))[.](#temp.spec.partial.general-4.sentence-4)
|
||
|
||
â *end example*]
|
||
|
||
[5](#temp.spec.partial.general-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3707)
|
||
|
||
The template argument list of a partial specialization is
|
||
the [*template-argument-list*](temp.names#nt:template-argument-list "13.3 Names of template specializations [temp.names]") following the name of the template[.](#temp.spec.partial.general-5.sentence-1)
|
||
|
||
[6](#temp.spec.partial.general-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3711)
|
||
|
||
A partial specialization may be declared in any
|
||
scope in which the corresponding primary template
|
||
may be defined ([[dcl.meaning]](dcl.meaning "9.3.4 Meaning of declarators"), [[class.mem]](class.mem "11.4 Class members"), [[temp.mem]](#temp.mem "13.7.3 Member templates"))[.](#temp.spec.partial.general-6.sentence-1)
|
||
|
||
[*Example [3](#temp.spec.partial.general-example-3)*: template<class T> struct A {struct C {template<class T2> struct B { }; template<class T2> struct B<T2**> { }; // partial specialization #1};};
|
||
|
||
// partial specialization of A<T>::C::B<T2>template<class T> template<class T2>struct A<T>::C::B<T2*> { }; // #2 A<short>::C::B<int*> absip; // uses partial specialization #2 â *end example*]
|
||
|
||
[7](#temp.spec.partial.general-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3732)
|
||
|
||
Partial specialization declarations do not introduce a name[.](#temp.spec.partial.general-7.sentence-1)
|
||
|
||
Instead, when the primary template name is used, any reachable partial
|
||
specializations of the primary template are also considered[.](#temp.spec.partial.general-7.sentence-2)
|
||
|
||
[*Note [1](#temp.spec.partial.general-note-1)*:
|
||
|
||
One consequence is
|
||
that a [*using-declaration*](namespace.udecl#nt:using-declaration "9.10 The using declaration [namespace.udecl]") which refers to a class template does not restrict the set of partial specializations
|
||
that are found through the [*using-declaration*](namespace.udecl#nt:using-declaration "9.10 The using declaration [namespace.udecl]")[.](#temp.spec.partial.general-7.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [4](#temp.spec.partial.general-example-4)*: namespace N {template<class T1, class T2> class A { }; // primary template}using N::A; // refers to the primary templatenamespace N {template<class T> class A<T, T*> { }; // partial specialization} A<int,int*> a; // uses the partial specialization, which is found through the using-declaration// which refers to the primary template â *end example*]
|
||
|
||
[8](#temp.spec.partial.general-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3759)
|
||
|
||
A constant template argument is non-specialized if it is the name of a constant
|
||
template parameter[.](#temp.spec.partial.general-8.sentence-1)
|
||
|
||
All other constant template arguments are specialized[.](#temp.spec.partial.general-8.sentence-2)
|
||
|
||
[9](#temp.spec.partial.general-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3764)
|
||
|
||
Within the argument list of a partial specialization,
|
||
the following restrictions apply:
|
||
|
||
- [(9.1)](#temp.spec.partial.general-9.1)
|
||
|
||
The type of a template parameter corresponding to a specialized constant template
|
||
argument shall not be dependent on a parameter of the partial specialization[.](#temp.spec.partial.general-9.1.sentence-1)
|
||
[*Example [5](#temp.spec.partial.general-example-5)*: template <class T, T t> struct C {};template <class T> struct C<T, 1>; // errortemplate< int X, int (*array_ptr)[X] > class A {};int array[5];template< int X > class A<X,&array> { }; // error â *end example*]
|
||
|
||
- [(9.2)](#temp.spec.partial.general-9.2)
|
||
|
||
The partial specialization shall be more specialized than the primary
|
||
template ([[temp.spec.partial.order]](#temp.spec.partial.order "13.7.6.3 Partial ordering of partial specializations"))[.](#temp.spec.partial.general-9.2.sentence-1)
|
||
|
||
- [(9.3)](#temp.spec.partial.general-9.3)
|
||
|
||
The template parameter list of a partial specialization shall not contain default
|
||
template argument values[.](#temp.spec.partial.general-9.3.sentence-1)[114](#footnote-114 "There is no context in which they would be used.")
|
||
|
||
- [(9.4)](#temp.spec.partial.general-9.4)
|
||
|
||
An argument shall not contain an unexpanded pack[.](#temp.spec.partial.general-9.4.sentence-1)
|
||
If
|
||
an argument is a pack expansion ([[temp.variadic]](#temp.variadic "13.7.4 Variadic templates")), it shall be
|
||
the last argument in the template argument list[.](#temp.spec.partial.general-9.4.sentence-2)
|
||
|
||
[10](#temp.spec.partial.general-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3797)
|
||
|
||
The usual access checking rules do not apply to non-dependent names
|
||
used to specify template arguments of the [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") of the partial specialization[.](#temp.spec.partial.general-10.sentence-1)
|
||
|
||
[*Note [2](#temp.spec.partial.general-note-2)*:
|
||
|
||
The template arguments can be private types or
|
||
objects that would normally not be accessible[.](#temp.spec.partial.general-10.sentence-2)
|
||
|
||
Dependent names cannot be checked when declaring the partial specialization,
|
||
but will be checked when substituting into the partial specialization[.](#temp.spec.partial.general-10.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[114)](#footnote-114)[114)](#footnoteref-114)
|
||
|
||
There is no context in which they would be used[.](#footnote-114.sentence-1)
|
||
|
||
#### [13.7.6.2](#temp.spec.partial.match) Matching of partial specializations [[temp.spec.partial.match]](temp.spec.partial.match)
|
||
|
||
[1](#temp.spec.partial.match-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3810)
|
||
|
||
When a template is used in a context that requires an instantiation of
|
||
the template,
|
||
it is necessary to determine whether the instantiation is to be generated
|
||
using the primary template or one of the partial specializations[.](#temp.spec.partial.match-1.sentence-1)
|
||
|
||
This is done by matching the template arguments of the template
|
||
specialization with the template argument lists of the partial
|
||
specializations[.](#temp.spec.partial.match-1.sentence-2)
|
||
|
||
- [(1.1)](#temp.spec.partial.match-1.1)
|
||
|
||
If exactly one matching partial specialization is found, the instantiation is
|
||
generated from that partial specialization[.](#temp.spec.partial.match-1.1.sentence-1)
|
||
|
||
- [(1.2)](#temp.spec.partial.match-1.2)
|
||
|
||
If more than one matching partial specialization is found,
|
||
the partial order rules ([[temp.spec.partial.order]](#temp.spec.partial.order "13.7.6.3 Partial ordering of partial specializations")) are used to determine
|
||
whether one of the partial specializations is more specialized than the
|
||
others[.](#temp.spec.partial.match-1.2.sentence-1)
|
||
If such a partial specialization exists,
|
||
the instantiation is generated from that partial specialization;
|
||
otherwise, the use of the template is ambiguous and the program is ill-formed[.](#temp.spec.partial.match-1.2.sentence-2)
|
||
|
||
- [(1.3)](#temp.spec.partial.match-1.3)
|
||
|
||
If no matches are found, the instantiation is generated from the
|
||
primary template[.](#temp.spec.partial.match-1.3.sentence-1)
|
||
|
||
[2](#temp.spec.partial.match-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3836)
|
||
|
||
A partial specialization matches a given actual template argument
|
||
list if the template arguments of the partial specialization can be[deduced](temp.deduct "13.10.3 Template argument deduction [temp.deduct]") from the actual template argument list,
|
||
and the deduced template arguments satisfy the [associated constraints](temp.constr.decl#def:associated_constraints "13.5.3 Constrained declarations [temp.constr.decl]") of the partial specialization, if any[.](#temp.spec.partial.match-2.sentence-1)
|
||
|
||
[*Example [1](#temp.spec.partial.match-example-1)*: template<class T1, class T2, int I> class A { }; // #1template<class T, int I> class A<T, T*, I> { }; // #2template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3template<class T> class A<int, T*, 5> { }; // #4template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5 A<int, int, 1> a1; // uses #1 A<int, int*, 1> a2; // uses #2, T is int, I is 1 A<int, char*, 5> a3; // uses #4, T is char A<int, char*, 1> a4; // uses #5, T1 is int, T2 is char, I is 1 A<int*, int*, 2> a5; // ambiguous: matches #3 and #5 â *end example*]
|
||
|
||
[*Example [2](#temp.spec.partial.match-example-2)*: template<typename T> concept C = requires (T t) { t.f(); };
|
||
|
||
template<typename T> struct S { }; // #1template<C T> struct S<T> { }; // #2struct Arg { void f(); };
|
||
|
||
S<int> s1; // uses #1; the constraints of #2 are not satisfied S<Arg> s2; // uses #2; both constraints are satisfied but #2 is more specialized â *end example*]
|
||
|
||
[3](#temp.spec.partial.match-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3871)
|
||
|
||
If the template arguments of a partial specialization cannot be deduced
|
||
because of the structure of its [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") and the [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]"),
|
||
the program is ill-formed[.](#temp.spec.partial.match-3.sentence-1)
|
||
|
||
[*Example [3](#temp.spec.partial.match-example-3)*: template <int I, int J> struct A {};template <int I> struct A<I+5, I*2> {}; // errortemplate <int I> struct A<I, I> {}; // OKtemplate <int I, int J, int K> struct B {};template <int I> struct B<I, I*2, 2> {}; // OK â *end example*]
|
||
|
||
[4](#temp.spec.partial.match-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3888)
|
||
|
||
In a name that refers to a specialization of a class or variable template
|
||
(e.g., A<int, int, 1>),
|
||
the argument list shall match the template parameter list of the primary
|
||
template[.](#temp.spec.partial.match-4.sentence-1)
|
||
|
||
The template arguments of a partial specialization are deduced from the arguments
|
||
of the primary template[.](#temp.spec.partial.match-4.sentence-2)
|
||
|
||
#### [13.7.6.3](#temp.spec.partial.order) Partial ordering of partial specializations [[temp.spec.partial.order]](temp.spec.partial.order)
|
||
|
||
[1](#temp.spec.partial.order-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3898)
|
||
|
||
For two partial specializations,
|
||
the first is [*more specialized*](temp.deduct.partial#def:more_specialized "13.10.3.5 Deducing template arguments during partial ordering [temp.deduct.partial]") than the second if, given the following
|
||
rewrite to two function templates, the first function template is more
|
||
specialized than the second according to the [ordering rules for function
|
||
templates](#temp.func.order "13.7.7.3 Partial ordering of function templates [temp.func.order]"):
|
||
|
||
- [(1.1)](#temp.spec.partial.order-1.1)
|
||
|
||
Each of the two
|
||
function templates has the same template parameters
|
||
and [associated constraints](temp.constr.decl#def:associated_constraints "13.5.3 Constrained declarations [temp.constr.decl]") as the corresponding partial specialization[.](#temp.spec.partial.order-1.1.sentence-1)
|
||
|
||
- [(1.2)](#temp.spec.partial.order-1.2)
|
||
|
||
Each function template
|
||
has a single function parameter
|
||
whose type is a class template specialization where the template arguments
|
||
are the corresponding template parameters from the function template
|
||
for each template argument
|
||
in the [*template-argument-list*](temp.names#nt:template-argument-list "13.3 Names of template specializations [temp.names]") of the [*simple-template-id*](temp.names#nt:simple-template-id "13.3 Names of template specializations [temp.names]") of the partial specialization[.](#temp.spec.partial.order-1.2.sentence-1)
|
||
|
||
[2](#temp.spec.partial.order-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3922)
|
||
|
||
[*Example [1](#temp.spec.partial.order-example-1)*: template<int I, int J, class T> class X { };template<int I, int J> class X<I, J, int> { }; // #1template<int I> class X<I, I, int> { }; // #2template<int I0, int J0> void f(X<I0, J0, int>); // Atemplate<int I0> void f(X<I0, I0, int>); // Btemplate <auto v> class Y { };template <auto* p> class Y<p> { }; // #3template <auto** pp> class Y<pp> { }; // #4template <auto* p0> void g(Y<p0>); // Ctemplate <auto** pp0> void g(Y<pp0>); // D
|
||
|
||
According to the ordering rules for function templates,
|
||
the function template*B* is more specialized than the function template*A* and
|
||
the function template*D* is more specialized than the function template*C*[.](#temp.spec.partial.order-2.sentence-1)
|
||
|
||
Therefore, the partial specialization #2
|
||
is more specialized than the partial specialization #1
|
||
and the partial specialization #4
|
||
is more specialized than the partial specialization #3[.](#temp.spec.partial.order-2.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[*Example [2](#temp.spec.partial.order-example-2)*: template<typename T> concept C = requires (T t) { t.f(); };template<typename T> concept D = C<T> && requires (T t) { t.f(); };
|
||
|
||
template<typename T> class S { };template<C T> class S<T> { }; // #1template<D T> class S<T> { }; // #2template<C T> void f(S<T>); // Atemplate<D T> void f(S<T>); // B
|
||
|
||
The partial specialization #2 is more specialized than #1
|
||
because B is more specialized than A[.](#temp.spec.partial.order-2.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
#### [13.7.6.4](#temp.spec.partial.member) Members of class template partial specializations [[temp.spec.partial.member]](temp.spec.partial.member)
|
||
|
||
[1](#temp.spec.partial.member-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L3973)
|
||
|
||
The members of the class template partial specialization are
|
||
unrelated to the members of the primary template[.](#temp.spec.partial.member-1.sentence-1)
|
||
|
||
Class template partial specialization members that are used in a way that
|
||
requires a definition shall be defined; the definitions of members of the
|
||
primary template are never used as definitions for members of a class
|
||
template partial specialization[.](#temp.spec.partial.member-1.sentence-2)
|
||
|
||
An explicit specialization of a member of a class template partial
|
||
specialization is declared in the same way as an explicit specialization of
|
||
a member of the primary template[.](#temp.spec.partial.member-1.sentence-3)
|
||
|
||
[*Example [1](#temp.spec.partial.member-example-1)*: // primary class templatetemplate<class T, int I> struct A {void f();};
|
||
|
||
// member of primary class templatetemplate<class T, int I> void A<T,I>::f() { }// class template partial specializationtemplate<class T> struct A<T,2> {void f(); void g(); void h();};
|
||
|
||
// member of class template partial specializationtemplate<class T> void A<T,2>::g() { }// explicit specializationtemplate<> void A<char,2>::h() { }int main() { A<char,0> a0;
|
||
A<char,2> a2;
|
||
a0.f(); // OK, uses definition of primary template's member a2.g(); // OK, uses definition of partial specialization's member a2.h(); // OK, uses definition of explicit specialization's member a2.f(); // error: no definition of f for A<T,2>; the primary template is not used here} â *end example*]
|
||
|
||
[2](#temp.spec.partial.member-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4017)
|
||
|
||
If a member template of a class template is partially specialized,
|
||
the member template partial specializations are member templates of
|
||
the enclosing class template;
|
||
if the enclosing class template is instantiated ([[temp.inst]](temp.inst "13.9.2 Implicit instantiation"), [[temp.explicit]](temp.explicit "13.9.3 Explicit instantiation")),
|
||
a declaration for every member template partial specialization is also
|
||
instantiated as part of creating the members of the class template
|
||
specialization[.](#temp.spec.partial.member-2.sentence-1)
|
||
|
||
If the primary member template is explicitly specialized for a given
|
||
(implicit) specialization of the enclosing class template,
|
||
the partial specializations of the member template are ignored for this
|
||
specialization of the enclosing class template[.](#temp.spec.partial.member-2.sentence-2)
|
||
|
||
If a partial specialization of the member template is explicitly specialized
|
||
for a given (implicit) specialization of the enclosing class template,
|
||
the primary member template and its other partial specializations are
|
||
still considered for this specialization of the enclosing class template[.](#temp.spec.partial.member-2.sentence-3)
|
||
|
||
[*Example [2](#temp.spec.partial.member-example-2)*: template<class T> struct A {template<class T2> struct B {}; // #1template<class T2> struct B<T2*> {}; // #2};
|
||
|
||
template<> template<class T2> struct A<short>::B {}; // #3 A<char>::B<int*> abcip; // uses #2 A<short>::B<int*> absip; // uses #3 A<char>::B<int> abci; // uses #1 â *end example*]
|
||
|
||
### [13.7.7](#temp.fct) Function templates [[temp.fct]](temp.fct)
|
||
|
||
#### [13.7.7.1](#temp.fct.general) General [[temp.fct.general]](temp.fct.general)
|
||
|
||
[1](#temp.fct.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4052)
|
||
|
||
A function template defines an unbounded set of related functions[.](#temp.fct.general-1.sentence-1)
|
||
|
||
[*Example [1](#temp.fct.general-example-1)*:
|
||
|
||
A family of sort functions can be declared like this:template<class T> class Array { };template<class T> void sort(Array<T>&);
|
||
|
||
â *end example*]
|
||
|
||
[2](#temp.fct.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4062)
|
||
|
||
[*Note [1](#temp.fct.general-note-1)*:
|
||
|
||
A function template can have the same name as other function templates
|
||
and non-template functions ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")) in the same scope[.](#temp.fct.general-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
A non-template function is not
|
||
related to a function template
|
||
(i.e., it is never considered to be a specialization),
|
||
even if it has the same name and type
|
||
as a potentially generated function template specialization[.](#temp.fct.general-2.sentence-2)[115](#footnote-115 "That is, declarations of non-template functions do not merely guide overload resolution of function template specializations with the same name. If such a non-template function is odr-used ([term.odr.use]) in a program, it must be defined; it will not be implicitly instantiated using the function template definition.")
|
||
|
||
[115)](#footnote-115)[115)](#footnoteref-115)
|
||
|
||
That is,
|
||
declarations of non-template functions do not merely guide
|
||
overload resolution of
|
||
function template specializations
|
||
with the same name[.](#footnote-115.sentence-1)
|
||
|
||
If such a non-template function is odr-used ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) in a program, it must be defined;
|
||
it will not be implicitly instantiated using the function template definition[.](#footnote-115.sentence-2)
|
||
|
||
#### [13.7.7.2](#temp.over.link) Function template overloading [[temp.over.link]](temp.over.link)
|
||
|
||
[1](#temp.over.link-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4084)
|
||
|
||
It is possible to overload function templates so that two different
|
||
function template specializations have the same type[.](#temp.over.link-1.sentence-1)
|
||
|
||
[*Example [1](#temp.over.link-example-1)*:
|
||
|
||
// translation unit 1:template<class T>void f(T*);void g(int* p) { f(p); // calls f<int>(int*)}
|
||
|
||
// translation unit 2:template<class T>void f(T);void h(int* p) { f(p); // calls f<int*>(int*)}
|
||
|
||
â *end example*]
|
||
|
||
[2](#temp.over.link-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4112)
|
||
|
||
Such specializations are distinct functions and do not violate the[one-definition rule](basic.def.odr "6.3 One-definition rule [basic.def.odr]")[.](#temp.over.link-2.sentence-1)
|
||
|
||
[3](#temp.over.link-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4116)
|
||
|
||
The signature of a function template
|
||
is defined in [[intro.defs]](intro.defs "3 Terms and definitions")[.](#temp.over.link-3.sentence-1)
|
||
|
||
The names of the template parameters are significant only for establishing
|
||
the relationship between the template parameters and the rest of the
|
||
signature[.](#temp.over.link-3.sentence-2)
|
||
|
||
[*Note [1](#temp.over.link-note-1)*:
|
||
|
||
Two distinct function templates can have identical function return types and
|
||
function parameter lists, even if overload resolution alone cannot distinguish
|
||
them[.](#temp.over.link-3.sentence-3)
|
||
|
||
template<class T> void f();template<int I> void f(); // OK, overloads the first template// distinguishable with an explicit template argument list â *end note*]
|
||
|
||
[4](#temp.over.link-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4134)
|
||
|
||
When an expression that references a template parameter is used in the
|
||
function parameter list or the return type in the declaration of a
|
||
function template, the expression that references the template
|
||
parameter is part of the signature of the function template[.](#temp.over.link-4.sentence-1)
|
||
|
||
This is
|
||
necessary to permit a declaration of a function template in one
|
||
translation unit to be linked with another declaration of the function
|
||
template in another translation unit and, conversely, to ensure that
|
||
function templates that are intended to be distinct are not linked
|
||
with one another[.](#temp.over.link-4.sentence-2)
|
||
|
||
[*Example [2](#temp.over.link-example-2)*: template <int I, int J> A<I+J> f(A<I>, A<J>); // #1template <int K, int L> A<K+L> f(A<K>, A<L>); // same as #1template <int I, int J> A<I-J> f(A<I>, A<J>); // different from #1 â *end example*]
|
||
|
||
[*Note [2](#temp.over.link-note-2)*:
|
||
|
||
Most expressions that use template parameters use constant template
|
||
parameters, but it is possible for an expression to reference a type
|
||
parameter[.](#temp.over.link-4.sentence-3)
|
||
|
||
For example, a template type parameter can be used in thesizeof operator[.](#temp.over.link-4.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[5](#temp.over.link-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4160)
|
||
|
||
Two expressions involving template parameters are considered[*equivalent*](#def:equivalent,expressions "13.7.7.2 Function template overloading [temp.over.link]") if two function definitions containing the expressions would satisfy
|
||
the [one-definition rule](basic.def.odr "6.3 One-definition rule [basic.def.odr]"), except that the tokens used
|
||
to name the template parameters may differ as long as a token used to
|
||
name a template parameter in one expression is replaced by another token
|
||
that names the same template parameter in the other expression[.](#temp.over.link-5.sentence-1)
|
||
|
||
Two unevaluated operands that do not involve template parameters
|
||
are considered equivalent
|
||
if two function definitions containing the expressions
|
||
would satisfy the one-definition rule,
|
||
except that the tokens used to name types and declarations may differ
|
||
as long as they name the same entities, and
|
||
the tokens used to form concept-ids ([[temp.names]](temp.names "13.3 Names of template specializations")) may differ
|
||
as long as the two [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]")*s* are the same ([[temp.type]](temp.type "13.6 Type equivalence"))[.](#temp.over.link-5.sentence-2)
|
||
|
||
[*Note [3](#temp.over.link-note-3)*:
|
||
|
||
For instance, A<42> and A<40+2> name the same type[.](#temp.over.link-5.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
Two [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")*s* are never considered equivalent[.](#temp.over.link-5.sentence-4)
|
||
|
||
[*Note [4](#temp.over.link-note-4)*:
|
||
|
||
The intent is to avoid [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]")*s* appearing in the
|
||
signature of a function template with external linkage[.](#temp.over.link-5.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
For determining whether two dependent names ([[temp.dep]](temp.dep "13.8.3 Dependent names")) are equivalent,
|
||
only the name itself is considered, not the result of name lookup[.](#temp.over.link-5.sentence-6)
|
||
|
||
[*Note [5](#temp.over.link-note-5)*:
|
||
|
||
If such a dependent name is unqualified,
|
||
it is looked up from
|
||
a first declaration of the function template ([[temp.res.general]](temp.res.general "13.8.1 General"))[.](#temp.over.link-5.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [3](#temp.over.link-example-3)*: template <int I, int J> void f(A<I+J>); // #1template <int K, int L> void f(A<K+L>); // same as #1template <class T> decltype(g(T())) h();int g(int);template <class T> decltype(g(T())) h() // redeclaration of h() uses the earlier lookup…{ return g(T()); } // … although the lookup here does find g(int)int i = h<int>(); // template argument substitution fails; g(int)// not considered at the first declaration of h()// ill-formed, no diagnostic required: the two expressions are functionally equivalent but not equivalenttemplate <int N> void foo(const char (*s)[([]{}, N)]);template <int N> void foo(const char (*s)[([]{}, N)]);
|
||
|
||
// two different declarations because the non-dependent portions are not considered equivalenttemplate <class T> void spam(decltype([]{}) (*s)[sizeof(T)]);template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]); â *end example*]
|
||
|
||
Two potentially-evaluated expressions involving template parameters that are not equivalent are[*functionally equivalent*](#def:functionally_equivalent,expressions "13.7.7.2 Function template overloading [temp.over.link]") if, for any given set of template arguments, the evaluation of the
|
||
expression results in the same value[.](#temp.over.link-5.sentence-8)
|
||
|
||
Two unevaluated operands that are not equivalent
|
||
are functionally equivalent if, for any given set of template arguments,
|
||
the expressions perform
|
||
the same operations in the same order with the same entities[.](#temp.over.link-5.sentence-9)
|
||
|
||
[*Note [6](#temp.over.link-note-6)*:
|
||
|
||
For instance, one could have redundant parentheses[.](#temp.over.link-5.sentence-10)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [4](#temp.over.link-example-4)*: template<int I> concept C = true;template<typename T> struct A {void f() requires C<42>; // #1void f() requires true; // OK, different functions}; â *end example*]
|
||
|
||
[6](#temp.over.link-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4235)
|
||
|
||
Two [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]")*s* are[*equivalent*](#def:equivalent,template-heads "13.7.7.2 Function template overloading [temp.over.link]") if
|
||
their [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]")*s* have the same length,
|
||
corresponding [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]")*s* are equivalent
|
||
and are both declared with [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")*s* that are equivalent
|
||
if either [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]") is declared with a [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]"),
|
||
and if either [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") has a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]"),
|
||
they both have[*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")*s* and the corresponding[*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")*s* are equivalent[.](#temp.over.link-6.sentence-1)
|
||
|
||
Two [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]")*s* are[*equivalent*](#def:equivalent,template-parameters "13.7.7.2 Function template overloading [temp.over.link]") under the following conditions:
|
||
|
||
- [(6.1)](#temp.over.link-6.1)
|
||
|
||
they declare template parameters of the same kind,
|
||
|
||
- [(6.2)](#temp.over.link-6.2)
|
||
|
||
if either declares a template parameter pack, they both do,
|
||
|
||
- [(6.3)](#temp.over.link-6.3)
|
||
|
||
if they declare constant template parameters,
|
||
they have equivalent types
|
||
ignoring the use of [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")*s* for placeholder types, and
|
||
|
||
- [(6.4)](#temp.over.link-6.4)
|
||
|
||
if they declare template template parameters,
|
||
their [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]")*s* are equivalent[.](#temp.over.link-6.sentence-2)
|
||
|
||
When determining whether types or [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")*s* are equivalent, the rules above are used to compare expressions
|
||
involving template parameters[.](#temp.over.link-6.sentence-3)
|
||
|
||
Two [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]")*s* are[*functionally equivalent*](#def:functionally_equivalent,template-heads "13.7.7.2 Function template overloading [temp.over.link]") if they accept and are satisfied by ([[temp.constr.constr]](temp.constr.constr "13.5.2 Constraints"))
|
||
the same set of template argument lists[.](#temp.over.link-6.sentence-4)
|
||
|
||
[7](#temp.over.link-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4267)
|
||
|
||
If the validity or meaning of the program depends on
|
||
whether two constructs are equivalent, and they are
|
||
functionally equivalent but not equivalent, the program is ill-formed,
|
||
no diagnostic required[.](#temp.over.link-7.sentence-1)
|
||
|
||
Furthermore, if two declarations A and B of function templates
|
||
|
||
- [(7.1)](#temp.over.link-7.1)
|
||
|
||
introduce the same name,
|
||
|
||
- [(7.2)](#temp.over.link-7.2)
|
||
|
||
have corresponding signatures ([[basic.scope.scope]](basic.scope.scope "6.4.1 General")),
|
||
|
||
- [(7.3)](#temp.over.link-7.3)
|
||
|
||
would declare the same entity,
|
||
when considering A and B to correspond in that determination ([[basic.link]](basic.link "6.7 Program and linkage")), and
|
||
|
||
- [(7.4)](#temp.over.link-7.4)
|
||
|
||
accept and are satisfied by the same set of template argument lists,
|
||
|
||
but do not correspond,
|
||
the program is ill-formed, no diagnostic required[.](#temp.over.link-7.sentence-2)
|
||
|
||
[8](#temp.over.link-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4287)
|
||
|
||
[*Note [7](#temp.over.link-note-7)*:
|
||
|
||
This rule guarantees that equivalent declarations will be linked with
|
||
one another, while not requiring implementations to use heroic efforts
|
||
to guarantee that functionally equivalent declarations will be treated
|
||
as distinct[.](#temp.over.link-8.sentence-1)
|
||
|
||
For example, the last two declarations are functionally
|
||
equivalent and would cause a program to be ill-formed:// guaranteed to be the sametemplate <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+10>);
|
||
|
||
// guaranteed to be differenttemplate <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+11>);
|
||
|
||
// ill-formed, no diagnostic requiredtemplate <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+1+2+3+4>);
|
||
|
||
â *end note*]
|
||
|
||
#### [13.7.7.3](#temp.func.order) Partial ordering of function templates [[temp.func.order]](temp.func.order)
|
||
|
||
[1](#temp.func.order-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4312)
|
||
|
||
If multiple function templates share a name,
|
||
the use of that name can be ambiguous because
|
||
template argument deduction ([[temp.deduct]](temp.deduct "13.10.3 Template argument deduction")) may identify
|
||
a specialization for more than one function template[.](#temp.func.order-1.sentence-1)
|
||
|
||
[*Partial ordering*](#def:template,function,partial_ordering "13.7.7.3 Partial ordering of function templates [temp.func.order]") of overloaded function template declarations is used in the following contexts
|
||
to select the function template to which a function template specialization
|
||
refers:
|
||
|
||
- [(1.1)](#temp.func.order-1.1)
|
||
|
||
during overload resolution for a call to a function template specialization ([[over.match.best]](over.match.best "12.2.4 Best viable function"));
|
||
|
||
- [(1.2)](#temp.func.order-1.2)
|
||
|
||
when the address of a function template specialization is taken;
|
||
|
||
- [(1.3)](#temp.func.order-1.3)
|
||
|
||
when a placement operator delete that is a
|
||
function template
|
||
specialization
|
||
is selected to match a placement operator new ([[basic.stc.dynamic.deallocation]](basic.stc.dynamic.deallocation "6.8.6.5.3 Deallocation functions"), [[expr.new]](expr.new "7.6.2.8 New"));
|
||
|
||
- [(1.4)](#temp.func.order-1.4)
|
||
|
||
when a [friend function declaration](#temp.friend "13.7.5 Friends [temp.friend]"), an[explicit instantiation](temp.explicit "13.9.3 Explicit instantiation [temp.explicit]") or an [explicit specialization](temp.expl.spec "13.9.4 Explicit specialization [temp.expl.spec]") refers to
|
||
a function template specialization[.](#temp.func.order-1.sentence-2)
|
||
|
||
[2](#temp.func.order-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4339)
|
||
|
||
Partial ordering selects which of two function templates is more
|
||
specialized than the other by transforming each template in turn
|
||
(see next paragraph) and performing template argument deduction
|
||
using the function type[.](#temp.func.order-2.sentence-1)
|
||
|
||
The deduction process determines whether
|
||
one of the templates is more specialized than the other[.](#temp.func.order-2.sentence-2)
|
||
|
||
If so, the
|
||
more specialized template is the one chosen by the partial ordering
|
||
process[.](#temp.func.order-2.sentence-3)
|
||
|
||
If both deductions succeed, the partial ordering selects
|
||
the more constrained template (if one exists) as determined below[.](#temp.func.order-2.sentence-4)
|
||
|
||
[3](#temp.func.order-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4351)
|
||
|
||
To produce the transformed template, for each
|
||
type, constant,
|
||
type template, variable template, or concept
|
||
template parameter (including template parameter packs ([[temp.variadic]](#temp.variadic "13.7.4 Variadic templates"))
|
||
thereof) synthesize a unique type, value, class template,
|
||
variable template, or concept,
|
||
respectively, and substitute it for each occurrence of that parameter
|
||
in the function type of the template[.](#temp.func.order-3.sentence-1)
|
||
|
||
[*Note [1](#temp.func.order-note-1)*:
|
||
|
||
The type replacing the placeholder
|
||
in the type of the value synthesized for a constant template parameter
|
||
is also a unique synthesized type[.](#temp.func.order-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[4](#temp.func.order-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4369)
|
||
|
||
A synthesized template has the same [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") as
|
||
its corresponding template template parameter[.](#temp.func.order-4.sentence-1)
|
||
|
||
[5](#temp.func.order-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4375)
|
||
|
||
Each function template M that is a member function
|
||
is considered to have
|
||
a new first parameter of type X(M), described below,
|
||
inserted in its function parameter list[.](#temp.func.order-5.sentence-1)
|
||
|
||
If exactly one of the function templates was considered by overload resolution
|
||
via a rewritten candidate ([[over.match.oper]](over.match.oper "12.2.2.3 Operators in expressions"))
|
||
with a reversed order of parameters,
|
||
then the order of the function parameters in its transformed template
|
||
is reversed[.](#temp.func.order-5.sentence-2)
|
||
|
||
For a function template M with cv-qualifiers cv that is a member of a class A:
|
||
|
||
- [(5.1)](#temp.func.order-5.1)
|
||
|
||
The type X(M) is ârvalue reference to cv Aâ
|
||
if the optional [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]") ofM is && or
|
||
if M has no [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]") and
|
||
the positionally-corresponding parameter of the other transformed template
|
||
has rvalue reference type;
|
||
if this determination depends recursively upon
|
||
whether X(M) is an rvalue reference type,
|
||
it is not considered to have rvalue reference type[.](#temp.func.order-5.1.sentence-1)
|
||
|
||
- [(5.2)](#temp.func.order-5.2)
|
||
|
||
Otherwise, X(M) is âlvalue reference to cv Aâ[.](#temp.func.order-5.2.sentence-1)
|
||
|
||
[*Note [2](#temp.func.order-note-2)*:
|
||
|
||
This allows a non-static
|
||
member to be ordered with respect to a non-member function and for the results
|
||
to be equivalent to the ordering of two equivalent non-members[.](#temp.func.order-5.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [1](#temp.func.order-example-1)*: struct A { };template<class T> struct B {template<class R> int operator*(R&); // #1};
|
||
|
||
template<class T, class R> int operator*(T&, R&); // #2// The declaration of B::operator* is transformed into the equivalent of// template<class R> int operator*(B<A>&, R&); // #1aint main() { A a;
|
||
B<A> b;
|
||
b * a; // calls #1} â *end example*]
|
||
|
||
[6](#temp.func.order-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4428)
|
||
|
||
Using the transformed function template's function type,
|
||
perform type deduction against the other template as described in [[temp.deduct.partial]](temp.deduct.partial "13.10.3.5 Deducing template arguments during partial ordering")[.](#temp.func.order-6.sentence-1)
|
||
|
||
[*Example [2](#temp.func.order-example-2)*: template<class T> struct A { A(); };
|
||
|
||
template<class T> void f(T);template<class T> void f(T*);template<class T> void f(const T*);
|
||
|
||
template<class T> void g(T);template<class T> void g(T&);
|
||
|
||
template<class T> void h(const T&);template<class T> void h(A<T>&);
|
||
|
||
void m() {const int* p;
|
||
f(p); // f(const T*) is more specialized than f(T) or f(T*)float x;
|
||
g(x); // ambiguous: g(T) or g(T&) A<int> z;
|
||
h(z); // overload resolution selects h(A<T>&)const A<int> z2;
|
||
h(z2); // h(const T&) is called because h(A<T>&) is not callable} â *end example*]
|
||
|
||
[7](#temp.func.order-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4459)
|
||
|
||
[*Note [3](#temp.func.order-note-3)*:
|
||
|
||
Since, in a call context, such type deduction considers only parameters
|
||
for which there are explicit call arguments, some parameters are ignored (namely,
|
||
function parameter packs, parameters with default arguments, and ellipsis
|
||
parameters)[.](#temp.func.order-7.sentence-1)
|
||
|
||
[*Example [3](#temp.func.order-example-3)*: template<class T> void f(T); // #1template<class T> void f(T*, int=1); // #2template<class T> void g(T); // #3template<class T> void g(T*, ...); // #4int main() {int* ip;
|
||
f(ip); // calls #2 g(ip); // calls #4} â *end example*]
|
||
|
||
[*Example [4](#temp.func.order-example-4)*: template<class T, class U> struct A { };
|
||
|
||
template<class T, class U> void f(U, A<U, T>* p = 0); // #1template< class U> void f(U, A<U, U>* p = 0); // #2template<class T > void g(T, T = T()); // #3template<class T, class... U> void g(T, U ...); // #4void h() { f<int>(42, (A<int, int>*)0); // calls #2 f<int>(42); // error: ambiguous g(42); // error: ambiguous} â *end example*]
|
||
|
||
[*Example [5](#temp.func.order-example-5)*: template<class T, class... U> void f(T, U...); // #1template<class T > void f(T); // #2template<class T, class... U> void g(T*, U...); // #3template<class T > void g(T); // #4void h(int i) { f(&i); // OK, calls #2 g(&i); // OK, calls #3} â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
[8](#temp.func.order-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4512)
|
||
|
||
If deduction against the other template succeeds for both transformed templates,
|
||
constraints can be considered as follows:
|
||
|
||
- [(8.1)](#temp.func.order-8.1)
|
||
|
||
If their [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]")*s* (possibly including [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]")*s* invented for an abbreviated function template ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))) or
|
||
function parameter lists differ in length,
|
||
neither template is more specialized than the other[.](#temp.func.order-8.1.sentence-1)
|
||
|
||
- [(8.2)](#temp.func.order-8.2)
|
||
|
||
Otherwise:
|
||
* [(8.2.1)](#temp.func.order-8.2.1)
|
||
|
||
If exactly one of the templates was considered by overload resolution
|
||
via a rewritten candidate with reversed order of parameters:
|
||
+
|
||
[(8.2.1.1)](#temp.func.order-8.2.1.1)
|
||
If, for either template, some of the template parameters
|
||
are not deducible from their function parameters,
|
||
neither template is more specialized than the other.
|
||
|
||
+
|
||
[(8.2.1.2)](#temp.func.order-8.2.1.2)
|
||
If there is either no reordering or more than one reordering
|
||
of the associated [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") such that
|
||
- [(8.2.1.2.1)](#temp.func.order-8.2.1.2.1)
|
||
|
||
the corresponding [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]")*s* of the [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]")*s* are equivalent and
|
||
|
||
- [(8.2.1.2.2)](#temp.func.order-8.2.1.2.2)
|
||
|
||
the function parameters that positionally correspond
|
||
between the two templates are of the same type,
|
||
|
||
neither template is more specialized than the other.
|
||
|
||
* [(8.2.2)](#temp.func.order-8.2.2)
|
||
|
||
Otherwise, if the corresponding [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]")*s* of the [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]")*s* are not equivalent ([[temp.over.link]](#temp.over.link "13.7.7.2 Function template overloading")) or
|
||
if the function parameters that positionally correspond
|
||
between the two templates are not of the same type,
|
||
neither template is more specialized than the other[.](#temp.func.order-8.2.sentence-1)
|
||
|
||
- [(8.3)](#temp.func.order-8.3)
|
||
|
||
Otherwise, if the context in which the partial ordering is done
|
||
is that of a call to a conversion function and
|
||
the return types of the templates are not the same,
|
||
then neither template is more specialized than the other[.](#temp.func.order-8.3.sentence-1)
|
||
|
||
- [(8.4)](#temp.func.order-8.4)
|
||
|
||
Otherwise,
|
||
if one template is more constrained than the other ([[temp.constr.order]](temp.constr.order "13.5.5 Partial ordering by constraints")),
|
||
the more constrained template is more specialized than the other[.](#temp.func.order-8.4.sentence-1)
|
||
|
||
- [(8.5)](#temp.func.order-8.5)
|
||
|
||
Otherwise, neither template is more specialized than the other[.](#temp.func.order-8.5.sentence-1)
|
||
|
||
[*Example [6](#temp.func.order-example-6)*: template <typename> constexpr bool True = true;template <typename T> concept C = True<T>;
|
||
|
||
void f(C auto &, auto &) = delete;template <C Q> void f(Q &, C auto &);
|
||
|
||
void g(struct A *ap, struct B *bp) { f(*ap, *bp); // OK, can use different methods to produce template parameters}template <typename T, typename U> struct X {};
|
||
|
||
template <typename T, C U, typename V> bool operator==(X<T, U>, V) = delete;template <C T, C U, C V> bool operator==(T, X<U, V>);
|
||
|
||
void h() { X<void *, int>{} == 0; // OK, correspondence of [T, U, V] and [U, V, T]} â *end example*]
|
||
|
||
### [13.7.8](#temp.alias) Alias templates [[temp.alias]](temp.alias)
|
||
|
||
[1](#temp.alias-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4592)
|
||
|
||
A [*template-declaration*](temp.pre#nt:template-declaration "13.1 Preamble [temp.pre]") in which the [*declaration*](dcl.pre#nt:declaration "9.1 Preamble [dcl.pre]") is an[*alias-declaration*](dcl.pre#nt:alias-declaration "9.1 Preamble [dcl.pre]") ([[dcl.pre]](dcl.pre "9.1 Preamble")) declares the[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") to be an [*alias template*](#def:template,alias "13.7.8 Alias templates [temp.alias]")[.](#temp.alias-1.sentence-1)
|
||
|
||
An alias template is a name for a family of
|
||
types[.](#temp.alias-1.sentence-2)
|
||
|
||
The name of the alias template is a [*template-name*](temp.names#nt:template-name "13.3 Names of template specializations [temp.names]")[.](#temp.alias-1.sentence-3)
|
||
|
||
[2](#temp.alias-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4599)
|
||
|
||
A
|
||
|
||
- [(2.1)](#temp.alias-2.1)
|
||
|
||
[*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") that is not the operand of a [*reflect-expression*](expr.reflect#nt:reflect-expression "7.6.2.10 The reflection operator [expr.reflect]") or
|
||
|
||
- [(2.2)](#temp.alias-2.2)
|
||
|
||
[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]")
|
||
|
||
that designates the specialization of
|
||
an alias template is equivalent to the associated type obtained by
|
||
substitution of its [*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]")*s* for the[*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]")*s* in the [*defining-type-id*](dcl.name#nt:defining-type-id "9.3.2 Type names [dcl.name]") of
|
||
the alias template[.](#temp.alias-2.sentence-1)
|
||
|
||
Any other [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") that names a specialization of an alias template is
|
||
a [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") for a type alias[.](#temp.alias-2.sentence-2)
|
||
|
||
[*Note [1](#temp.alias-note-1)*:
|
||
|
||
An alias template name is never deduced[.](#temp.alias-2.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [1](#temp.alias-example-1)*: template<class T> struct Alloc { /* ... */ };template<class T> using Vec = vector<T, Alloc<T>>;
|
||
Vec<int> v; // same as vector<int, Alloc<int>> v;template<class T>void process(Vec<T>& v){ /* ... */ }template<class T>void process(vector<T, Alloc<T>>& w){ /* ... */ } // error: redefinitiontemplate<template<class> class TT>void f(TT<int>);
|
||
|
||
f(v); // error: Vec not deducedtemplate<template<class,class> class TT>void g(TT<int, Alloc<int>>);
|
||
g(v); // OK, TT = vector â *end example*]
|
||
|
||
[3](#temp.alias-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4644)
|
||
|
||
However, if the [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") is dependent, subsequent template
|
||
argument substitution still applies to the [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]")[.](#temp.alias-3.sentence-1)
|
||
|
||
[*Example [2](#temp.alias-example-2)*: template<typename...> using void_t = void;template<typename T> void_t<typename T::foo> f();
|
||
f<int>(); // error: int does not have a nested type foo â *end example*]
|
||
|
||
[4](#temp.alias-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4655)
|
||
|
||
The [*defining-type-id*](dcl.name#nt:defining-type-id "9.3.2 Type names [dcl.name]") in an alias template declaration shall not refer to
|
||
the alias template being declared[.](#temp.alias-4.sentence-1)
|
||
|
||
The type produced by an alias template
|
||
specialization shall not directly or indirectly make use of that specialization[.](#temp.alias-4.sentence-2)
|
||
|
||
[*Example [3](#temp.alias-example-3)*: template <class T> struct A;template <class T> using B = typename A<T>::U;template <class T> struct A {typedef B<T> U;};
|
||
B<short> b; // error: instantiation of B<short> uses own type via A<short>::U â *end example*]
|
||
|
||
[5](#temp.alias-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4670)
|
||
|
||
The type of a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") appearing in an alias template declaration
|
||
is different between instantiations of that template,
|
||
even when the [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") is not dependent[.](#temp.alias-5.sentence-1)
|
||
|
||
[*Example [4](#temp.alias-example-4)*: template <class T>using A = decltype([] { }); // A<int> and A<char> refer to different closure types â *end example*]
|
||
|
||
### [13.7.9](#temp.concept) Concept definitions [[temp.concept]](temp.concept)
|
||
|
||
[1](#temp.concept-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4684)
|
||
|
||
A [*concept*](#def:concept "13.7.9 Concept definitions [temp.concept]") is a template
|
||
that defines constraints on its template arguments[.](#temp.concept-1.sentence-1)
|
||
|
||
[concept-definition:](#nt:concept-definition "13.7.9 Concept definitions [temp.concept]")
|
||
concept [*concept-name*](#nt:concept-name "13.7.9 Concept definitions [temp.concept]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt = [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") ;
|
||
|
||
[concept-name:](#nt:concept-name "13.7.9 Concept definitions [temp.concept]")
|
||
[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")
|
||
|
||
[2](#temp.concept-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4698)
|
||
|
||
A [*concept-definition*](#nt:concept-definition "13.7.9 Concept definitions [temp.concept]") declares a concept[.](#temp.concept-2.sentence-1)
|
||
|
||
Its [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") becomes a [*concept-name*](#nt:concept-name "13.7.9 Concept definitions [temp.concept]") referring to that concept
|
||
within its scope[.](#temp.concept-2.sentence-2)
|
||
|
||
The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") appertains to the concept[.](#temp.concept-2.sentence-3)
|
||
|
||
[*Example [1](#temp.concept-example-1)*: template<typename T>concept C = requires(T x) {{ x == x } -> std::[convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_to [concept.convertible]")<bool>;};
|
||
|
||
template<typename T>requires C<T> // C constrains f1(T) in [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") T f1(T x) { return x; }template<C T> // C, as a [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]"), constrains f2(T) T f2(T x) { return x; } â *end example*]
|
||
|
||
[3](#temp.concept-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4721)
|
||
|
||
A [*concept-definition*](#nt:concept-definition "13.7.9 Concept definitions [temp.concept]") shall inhabit a namespace scope ([[basic.scope.namespace]](basic.scope.namespace "6.4.6 Namespace scope"))[.](#temp.concept-3.sentence-1)
|
||
|
||
[4](#temp.concept-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4725)
|
||
|
||
A concept shall not have [associated constraints](temp.constr.decl#def:associated_constraints "13.5.3 Constrained declarations [temp.constr.decl]")[.](#temp.concept-4.sentence-1)
|
||
|
||
[5](#temp.concept-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4728)
|
||
|
||
A concept is not instantiated ([[temp.spec]](temp.spec "13.9 Template instantiation and specialization"))[.](#temp.concept-5.sentence-1)
|
||
|
||
[*Note [1](#temp.concept-note-1)*:
|
||
|
||
A concept-id ([[temp.names]](temp.names "13.3 Names of template specializations")) is evaluated as an expression[.](#temp.concept-5.sentence-2)
|
||
|
||
A concept cannot be
|
||
explicitly instantiated ([[temp.explicit]](temp.explicit "13.9.3 Explicit instantiation")),
|
||
explicitly specialized ([[temp.expl.spec]](temp.expl.spec "13.9.4 Explicit specialization")),
|
||
or partially specialized ([[temp.spec.partial]](#temp.spec.partial "13.7.6 Partial specialization"))[.](#temp.concept-5.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[6](#temp.concept-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4738)
|
||
|
||
The [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") of a [*concept-definition*](#nt:concept-definition "13.7.9 Concept definitions [temp.concept]") is an unevaluated operand ([[expr.context]](expr.context "7.2.3 Context dependence"))[.](#temp.concept-6.sentence-1)
|
||
|
||
[7](#temp.concept-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L4742)
|
||
|
||
The first declared template parameter of a concept definition is its[*prototype parameter*](#def:prototype_parameter,concept "13.7.9 Concept definitions [temp.concept]")[.](#temp.concept-7.sentence-1)
|
||
|
||
A [*type concept*](#def:concept,type "13.7.9 Concept definitions [temp.concept]") is a concept whose prototype parameter
|
||
is a type template parameter[.](#temp.concept-7.sentence-2)
|