[temp.decls] (original) (raw)
13 Templates [temp]
13.7 Template declarations [temp.decls]
13.7.1 General [temp.decls.general]
The template parameters of a template are specified in the angle bracket enclosed list that immediately follows the keyword template.
A primary template declaration is one in which the name of the template is not followed by a template-argument-list.
The template argument list of a primary template is the template argument list of its template-head ([temp.arg]).
A template declaration in which the name of the template is followed by a template-argument-list is a partial specialization ([temp.spec.partial]) of the template named in the declaration, which shall be a class or variable template.
For purposes of name lookup and instantiation, default arguments,type-constraints,requires-clauses ([temp.pre]), andnoexcept-specifier_s_of function templates and of member functions of class templates are considered definitions; each default argument,type-constraint,requires-clause, ornoexcept-specifieris a separate definition which is unrelated to the templated function definition or to any other default arguments,type-constraints,requires-clauses, ornoexcept-specifiers.
For the purpose of instantiation, the substatements of aconstexpr if statement are considered definitions.
13.7.2 Class templates [temp.class]
13.7.2.1 General [temp.class.general]
Aclass templatedefines the layout and operations for an unbounded set of related types.
[Example 1:
It is possible for a single class templateListto 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.
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 atype-name Tcan be used in the declaration.
In other words,Arrayis a parameterized type withTas its parameter.
— _end example_]
[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 thetemplate-head equivalent to that of the class template.
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.
The class template name in the member definition is followed by the template argument list of the template-head ([temp.arg]).
[Example 2: template<class T1, class T2> struct A { void f1();void f2();};template<class T2, class T1> void A<T2,T1>::f1() { } template<class T2, class T1> void A<T1,T2>::f2() { }
template<class ... Types> struct B { void f3();void f4();};template<class ... Types> void B<Types ...>::f3() { } template<class ... Types> void B<Types>::f4() { }
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() { } template<typename T> void S<T>::g() { } template<typename T> requires C<T> void S<T>::h() { } template<C X> template<D Y> struct S<X>::Inner { }; — _end example_]
— _end note_]
In a partial specialization, explicit specialization or explicit instantiation of a class template, the class-keyshall agree in kind with the original class template declaration ([dcl.type.elab]).
13.7.2.2 Member functions of class templates [temp.mem.func]
A member function of a class template may be defined outside of the class template definition in which it is declared.
[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.
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> { } template<typename T> void S<T>::g() { }
— _end example_]
Thetemplate-argument_s_for a member function of a class template are determined by thetemplate-argument_s_of the type of the object for which the member function is called.
[Example 2:
Thetemplate-argumentforArray<T>::operator[]will be determined by theArrayto which the subscripting operation is applied.
Array<int> v1(20); Array<dcomplex> v2(30); v1[3] = 7; v2[3] = dcomplex(7,8); — _end example_]
13.7.2.3 Deduction guides [temp.deduct.guide]
Deduction guides are not found by name lookup.
Instead, when performing class template argument deduction ([over.match.class.deduct]), all reachable deduction guides declared for the class template are considered.
[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()}; — _end example_]
A deduction-guideshall inhabit the scope to which the corresponding class template belongs and, for a member class template, have the same access.
Two deduction guide declarations for the same class template shall not have equivalent parameter-declaration-clause_s_if either is reachable from the other.
13.7.2.4 Member classes of class templates [temp.mem.class]
A member class of a class template may be defined outside the class template definition in which it is declared.
[Note 1:
The member class must be defined before its first use that requires an instantiation ([temp.inst]).
For example,template<class T> struct A { class B;}; A<int>::B* b1; template<class T> class A<T>::B { }; A<int>::B b2;
— _end note_]
13.7.2.5 Static data members of class templates [temp.static]
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.
[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; };template<class T> const T limits::min = { }; — _end example_]
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.
[Example 2: template <class T> struct A { static int i[];};template <class T> int A<T>::i[4]; template <> int A<int>::i[] = { 1 }; — _end example_]
13.7.2.6 Enumeration members of class templates [temp.mem.enum]
An enumeration member of a class template may be defined outside the class template definition.
[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 Member templates [temp.mem]
A template can be declared within a class or class template; such a template is called a member template.
A member template can be defined within or outside its class definition or class template definition.
A member template of a class template that is defined outside of its class template definition shall be specified with a template-head equivalent to that of the class template followed by a template-head equivalent to that of the member template ([temp.over.link]).
[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: 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) { } template<C1 T> template<typename U> void S<T>::g(U) { } — _end example_]
A local class of non-closure type shall not have member templates.
A destructor shall not be a member template.
A non-template member function ([dcl.fct]) 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.
When both exist, a use of that name and type refers to the non-template member unless an explicit template argument list is supplied.
[Example 3: template <class T> struct A { void f(int);template <class T2> void f(T2);};template <> void A<int>::f(int) { } template <> template <> void A<int>::f<>(int) { } int main() { A<char> ac; ac.f(1); ac.f('c'); ac.f<>(1); } — _end example_]
A member function template shall not be declared virtual.
[Example 4: template <class T> struct AA { template <class C> virtual void g(C); virtual void f(); }; — _end example_]
A specialization of a member function template does not override a virtual function from a base class.
[Example 5: class B { virtual void f(int);};class D : public B { template <class T> void f(T); void f(int i) { f<>(i); } }; — _end example_]
[Note 1:
A specialization of a conversion function template is referenced in the same way as a non-template conversion function that converts to the same type ([class.conv.fct]).
[Example 6: struct A { template <class T> operator T*();};template <class T> A::operator T*() { return 0; } template <> A::operator char*() { return 0; } template A::operator void*(); int main() { A a;int* ip; ip = a.operator int*(); } — _end example_]
— _end note_]
13.7.4 Variadic templates [temp.variadic]
A template parameter pack is a template parameter that accepts zero or more template arguments.
[Example 1: template<class ... Types> struct Tuple { }; Tuple<> t0; Tuple<int> t1; Tuple<int, float> t2; Tuple<0> error; — _end example_]
A function parameter pack is a function parameter that accepts zero or more function arguments.
[Example 2: template<class ... Types> void f(Types ... args); f(); f(1); f(2, 1.0); — _end example_]
[Example 3: template <typename... Args> void foo(Args... args) { [...xs=args]{ bar(xs...); };}foo(); foo(1); — _end example_]
[Example 4: auto foo() -> int(&)[2];template <class T> void g() { auto [...a] = foo(); auto [b, c, ...d] = foo(); } — _end example_]
A pack is a template parameter pack, a function parameter pack, an init-capture pack, or a structured binding pack.
The number of elements of a template parameter pack or a function parameter pack is the number of arguments provided for the parameter pack.
The number of elements of an init-capture pack is the number of elements in the pack expansion of its initializer.
A pack expansionconsists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list (described below).
The form of the pattern depends on the context in which the expansion occurs.
Pack expansions can occur in the following contexts:
- In a fold expanded constraint ([temp.constr.fold]); the pattern is the constraint of that fold expanded constraint.
[Example 5: template<class ... Types> void f(Types ... rest);template<class ... Types> void g(Types ... rest) { f(&rest ...); } — _end example_]
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.
A pack whose name appears within the pattern of a pack expansion is expanded by that pack expansion.
An appearance of the name of a pack is only expanded by the innermost enclosing pack expansion.
The pattern of a pack expansion shall name one or more packs that are not expanded by a nested pack expansion; such packs are calledunexpanded packs in the pattern.
All of the packs expanded by a pack expansion shall have the same number of arguments specified.
An appearance of a name of a pack that is not expanded is ill-formed.
[Example 6: template<typename...> struct Tuple {};template<typename T1, typename T2> struct Pair {};template<class ... Args1> struct zip { template<class ... Args2> struct with { typedef Tuple<Pair<Args1, Args2> ... > type;};};typedef zip<short, int>::with<unsigned short, unsigned>::type T1;typedef zip<short>::with<unsigned short, unsigned>::type T2;template<class ... Args> void g(Args ... args) { f(const_cast<const Args*>(&args)...); f(5 ...); f(args); f(h(args ...) + args ...); } — _end example_]
The instantiation of a pack expansion considers items , whereN is the number of elements in the pack expansion parameters.
Each is generated by instantiating the pattern and replacing each pack expansion parameter with its element.
Such an element, in the context of the instantiation, is interpreted as follows:
- if the pack is a template parameter pack, the element is
- an id-expression for a constant template parameter pack,
- a typedef-name for a type template parameter pack, or
- a template-name for a template template parameter pack
designating the corresponding type, template, or constant template argument;
- if the pack is a function parameter pack, the element is anid-expressiondesignating the function parameter that resulted from instantiation of the function parameter pack declaration;
- if the pack is an init-capture pack, the element is an id-expressiondesignating the variable introduced by the init-capturethat resulted from instantiation of the init-capture pack declaration; otherwise
- if the pack is a structured binding pack, the element is an id-expressiondesignating the 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.
The instantiation of a sizeof... expression ([expr.sizeof]) produces an integral constant with value N.
The instantiation of a fold-expression ([expr.prim.fold]) produces:
- ( (( op ) op ⋯) op )for a unary left fold,
- ( op (⋯ op ( op )) )for a unary right fold,
- ( (((E op ) op ) op ⋯) op )for a binary left fold, and
- ( op (⋯ op ( op ( op E))) )for a binary right fold.
For a binary fold,E is generated by instantiating the cast-expressionthat did not contain an unexpanded pack.
[Example 7: template<typename ...Args> bool all(Args ...args) { return (... && args); } bool b = all(true, true, true, false);
Within the instantiation of all, the returned expression expands to((true && true) && true) && false, which evaluates to false.
— _end example_]
If N is zero for a unary fold, the value of the expression is shown in Table 20; if the operator is not listed in Table 20, the instantiation is ill-formed.
The instantiation of any other pack expansion produces a list of elements .
When N is zero, the instantiation of the expansion produces an empty list.
[Example 8: template<class... T> struct X : T... { };template<class... T> void f(T... values) { X<T...> x(values...);} template void f<>(); — _end example_]
13.7.5 Friends [temp.friend]
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.
[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 thetaskclass template has the functionnext_timeas a friend; becauseprocessdoes not have explicittemplate-arguments, each specialization of thetaskclass template has an appropriately typed functionprocessas a friend, and this friend is not a function template specialization; because the friendpreempthas an explicittemplate-argument T, each specialization of thetaskclass template has the appropriate specialization of the function templatepreemptas a friend; and each specialization of thetaskclass template has all specializations of the function templatefuncas friends.
Similarly, each specialization of thetaskclass template has the class template specializationtask<int>as a friend, and has all specializations of the class templatefrdas friends.
— _end example_]
Friend classes, class templates, functions, or function templates can be declared within a class template.
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.
[Note 1:
They can introduce entities that belong to an enclosing namespace scope ([dcl.meaning]), in which case they are attached to the same module as the class template ([module.unit]).
— _end note_]
A friend template may be declared within a class or class template.
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.
In these cases, all specializations of the friend class or friend function template are friends of the class or class template granting friendship.
[Example 2: class A { template<class T> friend class B; template<class T> friend void f(T) { } }; — _end example_]
A template friend declaration specifies that all specializations of that template, whether they are implicitly instantiated ([temp.inst]), partially specialized ([temp.spec.partial]) or explicitly specialized ([temp.expl.spec]), are friends of the class containing the template friend declaration.
[Example 3: class X { template<class T> friend struct A;class Y { };};template<class T> struct A { X::Y ab; }; template<class T> struct A<T*> { X::Y ab; }; — _end example_]
A template friend declaration may declare a member of a dependent type to be a friend.
The template parameters of the template friend declaration shall be deducible from C ([temp.deduct.type]).
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.
[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; template<class T> friend void A<T>::f(); template<class T> friend void A<T>::D::g(); template<class T> friend int *A<T*>::h(); template<class T> template<T U> friend T A<T>::i(); }; — _end example_]
A friend template shall not be declared in a local class.
Friend declarations shall not declare partial specializations.
[Example 5: template<class T> class A { };class X { template<class T> friend class A<T*>; }; — _end example_]
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.
A non-template friend declaration with a requires-clauseshall be a definition.
A friend function template with a constraint that depends on a template parameter from an enclosing template shall be a definition.
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.
13.7.6 Partial specialization [temp.spec.partial]
13.7.6.1 General [temp.spec.partial.general]
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]).
A declaration of the primary template shall precede any partial specialization of that template.
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.
Two partial specialization declarations declare the same entity if they are partial specializations of the same template and have equivalenttemplate-heads and template argument lists ([temp.over.link]).
Each partial specialization is a distinct template.
[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.
The second and subsequent declarations declare partial specializations of the primary template.
— _end example_]
A partial specialization may be constrained ([temp.constr]).
[Example 2: template<typename T> concept C = true;template<typename T> struct X { };template<typename T> struct X<T*> { }; template<C T> struct X<T> { };
Both partial specializations are more specialized than the primary template.
#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.
#2 is more specialized because the template arguments are equivalent, but the partial specialization is more constrained ([temp.constr.order]).
— _end example_]
The template argument list of a partial specialization is the template-argument-list following the name of the template.
A partial specialization may be declared in any scope in which the corresponding primary template may be defined ([dcl.meaning], [class.mem], [temp.mem]).
[Example 3: template<class T> struct A { struct C { template<class T2> struct B { };template<class T2> struct B<T2**> { }; };};template<class T> template<class T2> struct A<T>::C::B<T2*> { }; A<short>::C::B<int*> absip; — _end example_]
Partial specialization declarations do not introduce a name.
Instead, when the primary template name is used, any reachable partial specializations of the primary template are also considered.
[Note 1:
One consequence is that a using-declarationwhich refers to a class template does not restrict the set of partial specializations that are found through the using-declaration.
— _end note_]
[Example 4: namespace N { template<class T1, class T2> class A { }; } using N::A; namespace N { template<class T> class A<T, T*> { }; }A<int,int*> a; — _end example_]
A constant template argument is non-specialized if it is the name of a constant template parameter.
All other constant template arguments are specialized.
Within the argument list of a partial specialization, the following restrictions apply:
- The type of a template parameter corresponding to a specialized constant template argument shall not be dependent on a parameter of the partial specialization.
[Example 5: template <class T, T t> struct C {};template <class T> struct C<T, 1>; template< int X, int (*array_ptr)[X] > class A {};int array[5];template< int X > class A<X,&array> { }; — _end example_] - The partial specialization shall be more specialized than the primary template ([temp.spec.partial.order]).
- The template parameter list of a partial specialization shall not contain default template argument values.114
- An argument shall not contain an unexpanded pack.
If an argument is a pack expansion ([temp.variadic]), it shall be the last argument in the template argument list.
The usual access checking rules do not apply to non-dependent names used to specify template arguments of the simple-template-idof the partial specialization.
[Note 2:
The template arguments can be private types or objects that would normally not be accessible.
Dependent names cannot be checked when declaring the partial specialization, but will be checked when substituting into the partial specialization.
— _end note_]
13.7.6.2 Matching of partial specializations [temp.spec.partial.match]
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.
This is done by matching the template arguments of the template specialization with the template argument lists of the partial specializations.
- If exactly one matching partial specialization is found, the instantiation is generated from that partial specialization.
- If more than one matching partial specialization is found, the partial order rules ([temp.spec.partial.order]) are used to determine whether one of the partial specializations is more specialized than the others.
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. - If no matches are found, the instantiation is generated from the primary template.
A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can bededuced from the actual template argument list, and the deduced template arguments satisfy the associated constraintsof the partial specialization, if any.
[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> { }; A<int, int, 1> a1; A<int, int*, 1> a2; A<int, char*, 5> a3; A<int, char*, 1> a4; A<int*, int*, 2> a5; — _end example_]
[Example 2: template<typename T> concept C = requires (T t) { t.f(); };template<typename T> struct S { }; template<C T> struct S<T> { }; struct Arg { void f(); }; S<int> s1; S<Arg> s2; — _end example_]
If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-listand the template-id, the program is ill-formed.
[Example 3: template <int I, int J> struct A {};template <int I> struct A<I+5, I*2> {}; template <int I> struct A<I, I> {}; template <int I, int J, int K> struct B {};template <int I> struct B<I, I*2, 2> {}; — _end example_]
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.
The template arguments of a partial specialization are deduced from the arguments of the primary template.
13.7.6.3 Partial ordering of partial specializations [temp.spec.partial.order]
For two partial specializations, the first is more specialized 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:
- Each of the two function templates has the same template parameters and associated constraintsas the corresponding partial specialization.
- 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-listof the simple-template-idof the partial specialization.
[Example 1: template<int I, int J, class T> class X { };template<int I, int J> class X<I, J, int> { }; template<int I> class X<I, I, int> { }; template<int I0, int J0> void f(X<I0, J0, int>); template<int I0> void f(X<I0, I0, int>); template <auto v> class Y { };template <auto* p> class Y<p> { }; template <auto** pp> class Y<pp> { }; template <auto* p0> void g(Y<p0>); template <auto** pp0> void g(Y<pp0>);
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_.
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.
— _end example_]
[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> { }; template<D T> class S<T> { }; template<C T> void f(S<T>); template<D T> void f(S<T>);
The partial specialization #2 is more specialized than #1 because B is more specialized than A.
— _end example_]
13.7.6.4 Members of class template partial specializations [temp.spec.partial.member]
The members of the class template partial specialization are unrelated to the members of the primary template.
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.
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.
[Example 1: template<class T, int I> struct A { void f();};template<class T, int I> void A<T,I>::f() { } template<class T> struct A<T,2> { void f();void g();void h();};template<class T> void A<T,2>::g() { } template<> void A<char,2>::h() { } int main() { A<char,0> a0; A<char,2> a2; a0.f(); a2.g(); a2.h(); a2.f(); } — _end example_]
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.explicit]), a declaration for every member template partial specialization is also instantiated as part of creating the members of the class template specialization.
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.
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.
[Example 2: template<class T> struct A { template<class T2> struct B {}; template<class T2> struct B<T2*> {}; };template<> template<class T2> struct A<short>::B {}; A<char>::B<int*> abcip; A<short>::B<int*> absip; A<char>::B<int> abci; — _end example_]
13.7.7 Function templates [temp.fct]
13.7.7.1 General [temp.fct.general]
A function template defines an unbounded set of related functions.
[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_]
[Note 1:
A function template can have the same name as other function templates and non-template functions ([dcl.fct]) in the same scope.
— _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.115
13.7.7.2 Function template overloading [temp.over.link]
It is possible to overload function templates so that two different function template specializations have the same type.
[Example 1:
template<class T> void f(T*);void g(int* p) { f(p); }
template<class T> void f(T);void h(int* p) { f(p); }
— _end example_]
The signature of a function template is defined in [intro.defs].
The names of the template parameters are significant only for establishing the relationship between the template parameters and the rest of the signature.
[Note 1:
Two distinct function templates can have identical function return types and function parameter lists, even if overload resolution alone cannot distinguish them.
template<class T> void f();template<int I> void f(); — _end note_]
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.
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.
[Example 2: template <int I, int J> A<I+J> f(A<I>, A<J>); template <int K, int L> A<K+L> f(A<K>, A<L>); template <int I, int J> A<I-J> f(A<I>, A<J>); — _end example_]
[Note 2:
Most expressions that use template parameters use constant template parameters, but it is possible for an expression to reference a type parameter.
For example, a template type parameter can be used in thesizeof operator.
— _end note_]
Two expressions involving template parameters are consideredequivalentif two function definitions containing the expressions would satisfy the one-definition rule, 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.
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]) may differ as long as the two template-ids are the same ([temp.type]).
[Note 3:
For instance, A<42> and A<40+2> name the same type.
— _end note_]
[Note 4:
The intent is to avoid lambda-expressions appearing in the signature of a function template with external linkage.
— _end note_]
For determining whether two dependent names ([temp.dep]) are equivalent, only the name itself is considered, not the result of name lookup.
[Note 5:
If such a dependent name is unqualified, it is looked up from a first declaration of the function template ([temp.res.general]).
— _end note_]
[Example 3: template <int I, int J> void f(A<I+J>); template <int K, int L> void f(A<K+L>); template <class T> decltype(g(T())) h();int g(int);template <class T> decltype(g(T())) h() { return g(T()); } int i = h<int>(); template <int N> void foo(const char (*s)[([]{}, N)]);template <int N> void foo(const char (*s)[([]{}, N)]);template <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 arefunctionally equivalentif, for any given set of template arguments, the evaluation of the expression results in the same value.
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.
[Note 6:
For instance, one could have redundant parentheses.
— _end note_]
[Example 4: template<int I> concept C = true;template<typename T> struct A { void f() requires C<42>; void f() requires true; }; — _end example_]
Two template-parameters areequivalentunder the following conditions:
- they declare template parameters of the same kind,
- if either declares a template parameter pack, they both do,
- if they declare constant template parameters, they have equivalent types ignoring the use of type-constraints for placeholder types, and
- if they declare template template parameters, their kinds are the same and their template-heads are equivalent.
When determining whether types or type-constraint_s_are equivalent, the rules above are used to compare expressions involving template parameters.
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.
Furthermore, if two declarations A and B of function templates
- introduce the same name,
- have corresponding signatures ([basic.scope.scope]),
- would declare the same entity, when considering A and B to correspond in that determination ([basic.link]), and
- accept and are satisfied by the same set of template argument lists,
but do not correspond, the program is ill-formed, no diagnostic required.
[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.
For example, the last two declarations are functionally equivalent and would cause a program to be ill-formed: template <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+10>);template <int I> void f(A<I>, A<I+11>);template <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 Partial ordering of function templates [temp.func.order]
If multiple function templates share a name, the use of that name can be ambiguous because template argument deduction ([temp.deduct]) may identify a specialization for more than one function template.
Partial orderingof overloaded function template declarations is used in the following contexts to select the function template to which a function template specialization refers:
- during overload resolution for a call to a function template specialization ([over.match.best]);
- when the address of a function template specialization is taken;
- when a placement operator delete that is a function template specialization is selected to match a placement operator new ([basic.stc.dynamic.deallocation], [expr.new]);
- when a friend function declaration, anexplicit instantiation or an explicit specialization refers to a function template specialization.
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.
The deduction process determines whether one of the templates is more specialized than the other.
If so, the more specialized template is the one chosen by the partial ordering process.
If both deductions succeed, the partial ordering selects the more constrained template (if one exists) as determined below.
To produce the transformed template, for each type, constant, type template, variable template, or concept template parameter (including template parameter packs ([temp.variadic]) 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.
[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.
— _end note_]
A synthesized template has the same template-head as its corresponding template template parameter.
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.
If exactly one of the function templates was considered by overload resolution via a rewritten candidate ([over.match.oper]) with a reversed order of parameters, then the order of the function parameters in its transformed template is reversed.
For a function template M with cv-qualifiers cvthat is a member of a class A:
- The type X(M) is “rvalue reference to cv A” if the optional ref-qualifier ofM is && or if M has no ref-qualifier 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.
- Otherwise, X(M) is “lvalue reference to cv A”.
[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.
— _end note_]
[Example 1: struct A { };template<class T> struct B { template<class R> int operator*(R&); };template<class T, class R> int operator*(T&, R&); int main() { A a; B<A> b; b * a; } — _end example_]
Using the transformed function template's function type, perform type deduction against the other template as described in [temp.deduct.partial].
[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); float x; g(x); A<int> z; h(z); const A<int> z2; h(z2); } — _end example_]
[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).
[Example 3: template<class T> void f(T); template<class T> void f(T*, int=1); template<class T> void g(T); template<class T> void g(T*, ...); int main() { int* ip; f(ip); g(ip); } — _end example_]
[Example 4: template<class T, class U> struct A { };template<class T, class U> void f(U, A<U, T>* p = 0); template< class U> void f(U, A<U, U>* p = 0); template<class T > void g(T, T = T()); template<class T, class... U> void g(T, U ...); void h() { f<int>(42, (A<int, int>*)0); f<int>(42); g(42); } — _end example_]
[Example 5: template<class T, class... U> void f(T, U...); template<class T > void f(T); template<class T, class... U> void g(T*, U...); template<class T > void g(T); void h(int i) { f(&i); g(&i); } — _end example_]
— _end note_]
If deduction against the other template succeeds for both transformed templates, constraints can be considered as follows:
- Otherwise:
- If exactly one of the templates was considered by overload resolution via a rewritten candidate with reversed order of parameters:
* If, for either template, some of the template parameters are not deducible from their function parameters, neither template is more specialized than the other.
* If there is either no reordering or more than one reordering of the associated template-parameter-listsuch that
* the corresponding template-parameter_s_of the template-parameter-lists are equivalent and
* the function parameters that positionally correspond between the two templates are of the same type,
neither template is more specialized than the other. - Otherwise, if the corresponding template-parameter_s_of the template-parameter-list_s_are not equivalent ([temp.over.link]) 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.
- If exactly one of the templates was considered by overload resolution via a rewritten candidate with reversed order of parameters:
- 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.
- Otherwise, if one template is more constrained than the other ([temp.constr.order]), the more constrained template is more specialized than the other.
- Otherwise, neither template is more specialized than the other.
[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); } 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; } — _end example_]
13.7.8 Alias templates [temp.alias]
An alias template is a name for a family of types.
[Note 1:
An alias template name is never deduced.
— _end note_]
[Example 1: template<class T> struct Alloc { };template<class T> using Vec = vector<T, Alloc<T>>; Vec<int> v; template<class T> void process(Vec<T>& v) { } template<class T> void process(vector<T, Alloc<T>>& w) { } template<template<class> class TT> void f(TT<int>); f(v); template<template<class,class> class TT> void g(TT<int, Alloc<int>>); g(v); — _end example_]
However, if the template-id is dependent, subsequent template argument substitution still applies to the template-id.
[Example 2: template<typename...> using void_t = void;template<typename T> void_t<typename T::foo> f(); f<int>(); — _end example_]
The defining-type-id in an alias template declaration shall not refer to the alias template being declared.
The type produced by an alias template specialization shall not directly or indirectly make use of that specialization.
[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; — _end example_]
The type of a lambda-expressionappearing in an alias template declaration is different between instantiations of that template, even when the lambda-expression is not dependent.
[Example 4: template <class T> using A = decltype([] { }); — _end example_]
13.7.9 Concept definitions [temp.concept]
A concept is a template that defines constraints on its template arguments.
A concept-definitiondeclares a concept.
Its identifier becomes a concept-namereferring to that concept within its scope.
[Example 1: template<typename T> concept C = requires(T x) { { x == x } -> std::convertible_to<bool>;};template<typename T> requires C<T>T f1(T x) { return x; } template<C T>T f2(T x) { return x; } — _end example_]
The first declared template parameter of a concept definition is itsprototype parameter.
A type conceptis a concept whose prototype parameter is a type template parameter.