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

484 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

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

[temp.arg]
# 13 Templates [[temp]](./#temp)
## 13.4 Template arguments [temp.arg]
### [13.4.1](#general) General [[temp.arg.general]](temp.arg.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1009)
The type and form of each [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") specified
in a [*template-id*](temp.names#nt:template-id "13.3Names of template specializations[temp.names]") or
in a [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]") shall match the type and form specified for the corresponding
parameter declared by the template in its[*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1Preamble[temp.pre]")[.](#general-1.sentence-1)
When the parameter declared by the template is a[template parameter pack](temp.variadic#def:template_parameter_pack "13.7.4Variadic templates[temp.variadic]"), it will correspond to zero or more[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")*s*[.](#general-1.sentence-2)
[*Example [1](#general-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]; }};
Array<int> v1(20);typedef std::complex<double> dcomplex; // std::complex is a standard library template Array<dcomplex> v2(30);
Array<dcomplex> v3(40);
void bar() { v1[3] = 7;
v2[3] = v3.elem(4) = dcomplex(7,8);} — *end example*]
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1043)
The template argument list of a [*template-head*](temp.pre#nt:template-head "13.1Preamble[temp.pre]") is
a template argument list in which the nth template argument
has the value of
the nth template parameter of the [*template-head*](temp.pre#nt:template-head "13.1Preamble[temp.pre]")[.](#general-2.sentence-1)
If the nth template parameter is
a template parameter pack ([[temp.variadic]](temp.variadic "13.7.4Variadic templates")),
the nth template argument is a pack expansion
whose pattern is the name of the template parameter pack[.](#general-2.sentence-2)
[3](#general-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1053)
In a[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]"),
an ambiguity between a[*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]") and an expression is resolved to a[*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]"),
regardless of the form of the corresponding[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]")[.](#general-3.sentence-1)[109](#footnote-109 "There is no such ambiguity in a default template-argument because the form of the template-parameter determines the allowable forms of the template-argument.")
[*Example [2](#general-example-2)*: template<class T> void f();template<int I> void f();
void g() { f<int()>(); // int() is a type-id: call the first f()} — *end example*]
[4](#general-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1081)
[*Note [1](#general-note-1)*:
Names used in a [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") are subject to access control where they appear[.](#general-4.sentence-1)
Because a template parameter is not a class member,
no access control applies where the template parameter is used[.](#general-4.sentence-2)
— *end note*]
[*Example [3](#general-example-3)*: template<class T> class X {static T t;};
class Y {private:struct S { /* ... */ };
X<S> x; // OK, S is accessible// X<Y::S> has a static member of type Y::S// OK, even though Y::S is private};
X<Y::S> y; // error: S not accessible — *end example*]
For a template argument that is a class type or a class template,
the template definition has no special access rights
to the members of the template argument[.](#general-4.sentence-3)
[*Example [4](#general-example-4)*: template <template <class TT> class T> class A {typename T<int>::S s;};
template <class U> class B {private:struct S { /* ... */ };};
A<B> b; // error: A has no access to B::S — *end example*]
[5](#general-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1123)
When template argument packs or default template arguments are used,
a [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") list can be empty[.](#general-5.sentence-1)
In that case the empty<> brackets shall still be used as the[*template-argument-list*](temp.names#nt:template-argument-list "13.3Names of template specializations[temp.names]")[.](#general-5.sentence-2)
[*Example [5](#general-example-5)*: template<class T = char> class String;
String<>* p; // OK, String<char> String* q; // syntax errortemplate<class ... Elements> class Tuple;
Tuple<>* t; // OK, Elements is empty Tuple* u; // syntax error — *end example*]
[6](#general-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1141)
An explicit destructor call ([[class.dtor]](class.dtor "11.4.7Destructors")) for an object that has a type
that is a class template specialization may explicitly specify the[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")*s*[.](#general-6.sentence-1)
[*Example [6](#general-example-6)*: template<class T> struct A {~A();};void f(A<int>* p, A<int>* q) { p->A<int>::~A(); // OK, destructor call q->A<int>::~A<int>(); // OK, destructor call} — *end example*]
[7](#general-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1157)
If the use of a template argument
gives rise to an ill-formed construct in the instantiation of a
template specialization, the program is ill-formed[.](#general-7.sentence-1)
[8](#general-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1162)
When name lookup for the component name of a[*template-id*](temp.names#nt:template-id "13.3Names of template specializations[temp.names]") finds an overload set, both non-template functions in the overload
set and function templates in the overload set for
which the[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")*s* do not match the[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]")*s* are ignored[.](#general-8.sentence-1)
[*Note [2](#general-note-2)*:
If none of the function templates have matching[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]")*s*,
the program is ill-formed[.](#general-8.sentence-2)
— *end note*]
[9](#general-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1178)
When a [*simple-template-id*](temp.names#nt:simple-template-id "13.3Names of template specializations[temp.names]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6Splice specifiers[basic.splice]") does not designate a function,
a default [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") is[implicitly instantiated](temp.inst "13.9.2Implicit instantiation[temp.inst]") when the value of that default argument is needed[.](#general-9.sentence-1)
[*Example [7](#general-example-7)*: template<typename T, typename U = int> struct S { };
S<bool>* p; // the type of p is S<bool, int>*
The default argument for U is instantiated to form the type S<bool, int>*[.](#general-9.sentence-2)
— *end example*]
[10](#general-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1193)
A [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") followed by an ellipsis is
a [pack expansion](temp.variadic#def:pack_expansion "13.7.4Variadic templates[temp.variadic]")[.](#general-10.sentence-1)
[109)](#footnote-109)[109)](#footnoteref-109)
There is no such ambiguity in a default[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") because the form of the[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]") determines the allowable forms of the[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")[.](#footnote-109.sentence-1)
### [13.4.2](#type) Type template arguments [[temp.arg.type]](temp.arg.type)
[1](#type-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1199)
A[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") for a type template parameter
shall be a[*type-id*](dcl.name#nt:type-id "9.3.2Type names[dcl.name]")[.](#type-1.sentence-1)
[2](#type-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1206)
[*Example [1](#type-example-1)*: template <class T> class X { };template <class T> void f(T t) { }struct { } unnamed_obj;
void f() {struct A { }; enum { e1 }; typedef struct { } B;
B b;
X<A> x1; // OK X<A*> x2; // OK X<B> x3; // OK f(e1); // OK f(unnamed_obj); // OK f(b); // OK} — *end example*]
[*Note [1](#type-note-1)*:
A template type argument can be an incomplete type ([[basic.types.general]](basic.types.general#term.incomplete.type "6.9.1General"))[.](#type-2.sentence-1)
— *end note*]
### [13.4.3](#nontype) Constant template arguments [[temp.arg.nontype]](temp.arg.nontype)
[1](#nontype-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1233)
A template argument E for
a constant template parameter with declared type T shall be such that the invented declarationT x = E ; satisfies the semantic constraints for the definition of
a constexpr variable with static storage duration ([[dcl.constexpr]](dcl.constexpr "9.2.6The constexpr and consteval specifiers"))[.](#nontype-1.sentence-1)
If T contains a placeholder type ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7Placeholder type specifiers"))
or a placeholder for a deduced class type ([[dcl.type.class.deduct]](dcl.type.class.deduct "9.2.9.8Deduced class template specialization types")),
the type of the parameter is deduced from the above declaration[.](#nontype-1.sentence-2)
[*Note [1](#nontype-note-1)*:
E is a [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") or
(for a default template argument) an [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1General[dcl.init.general]")[.](#nontype-1.sentence-3)
— *end note*]
If the parameter type thus deduced is not permitted
for a constant template parameter ([[temp.param]](temp.param "13.2Template parameters")),
the program is ill-formed[.](#nontype-1.sentence-4)
[2](#nontype-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1253)
The value of a constant template parameter P of (possibly deduced) type T is determined from its template argument A as follows[.](#nontype-2.sentence-1)
If T is not a class type andA is not a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1General[dcl.init.general]"),A shall be a converted constant expression ([[expr.const]](expr.const "7.7Constant expressions"))
of type T; the value of P is A (as converted)[.](#nontype-2.sentence-2)
[3](#nontype-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1262)
Otherwise, a temporary variableconstexpr T v = A; is introduced[.](#nontype-3.sentence-1)
The lifetime of v ends immediately after initializing it and
any template parameter object (see below)[.](#nontype-3.sentence-2)
For each such variable,
the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") v is termed a [*candidate initializer*](#def:candidate_initializer "13.4.3Constant template arguments[temp.arg.nontype]")[.](#nontype-3.sentence-3)
[4](#nontype-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1274)
If T is a class type,
a template parameter object ([[temp.param]](temp.param "13.2Template parameters")) exists
that is constructed so as to be template-argument-equivalent to v;P denotes that template parameter object[.](#nontype-4.sentence-1)
P is copy-initialized from an unspecified candidate initializer
that is template-argument-equivalent to v[.](#nontype-4.sentence-2)
If, for the initialization from any candidate initializer,
- [(4.1)](#nontype-4.1)
the initialization would be ill-formed, or
- [(4.2)](#nontype-4.2)
the full-expression of an invented [*init-declarator*](dcl.decl.general#nt:init-declarator "9.3.1General[dcl.decl.general]") for the initialization would not be a constant expression
when interpreted as a [*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]") ([[expr.const]](expr.const "7.7Constant expressions")), or
- [(4.3)](#nontype-4.3)
the initialization would cause P to not be template-argument-equivalent ([[temp.type]](temp.type "13.6Type equivalence")) to v,
the program is ill-formed[.](#nontype-4.sentence-3)
[5](#nontype-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1294)
Otherwise, the value of P is that of v[.](#nontype-5.sentence-1)
[6](#nontype-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1297)
For a constant template parameter of reference or pointer type,
or for each non-static data member of reference or pointer type
in a constant template parameter of class type or subobject thereof,
the reference or pointer value shall not refer
or point to (respectively):
- [(6.1)](#nontype-6.1)
a temporary object ([[class.temporary]](class.temporary "6.8.7Temporary objects")),
- [(6.2)](#nontype-6.2)
a string literal object ([[lex.string]](lex.string "5.13.5String literals")),
- [(6.3)](#nontype-6.3)
the result of a typeid expression ([[expr.typeid]](expr.typeid "7.6.1.8Type identification")),
- [(6.4)](#nontype-6.4)
a predefined __func__ variable ([[dcl.fct.def.general]](dcl.fct.def.general "9.6.1General")), or
- [(6.5)](#nontype-6.5)
a subobject ([[intro.object]](intro.object "6.8.2Object model")) of one of the above[.](#nontype-6.sentence-1)
[7](#nontype-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1311)
[*Example [1](#nontype-example-1)*: template <int& r> class A{};extern int x;
A<x> a; // OKvoid f(int p) {constexpr int& r = p; // OK A<r> a; // error: a static constexpr int& variable cannot be initialized to refer to p here} — *end example*]
[8](#nontype-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1324)
[*Example [2](#nontype-example-2)*: template<const int* pci> struct X { /* ... */ };int ai[10];
X<ai> xi; // array to pointer and qualification conversionsstruct Y { /* ... */ };template<const Y& b> struct Z { /* ... */ };
Y y;
Z<y> z; // no conversion, but note extra cv-qualificationtemplate<int (&pa)[5]> struct W { /* ... */ };int b[5];
W<b> w; // no conversionvoid f(char);void f(int);
template<void (*pf)(int)> struct A { /* ... */ };
A<&f> a; // selects f(int)template<auto n> struct B { /* ... */ };
B<5> b1; // OK, template parameter type is int B<'a'> b2; // OK, template parameter type is char B<2.5> b3; // OK, template parameter type is double B<void(0)> b4; // error: template parameter type cannot be voidtemplate<int i> struct C { /* ... */ };
C<{ 42 }> c1; // OKstruct J1 { J1 *self = this;};
B<J1{}> j1; // error: initialization of template parameter object is not a constant expressionstruct J2 { J2 *self = this; constexpr J2() {}constexpr J2(const J2&) {}};
B<J2{}> j2; // error: template parameter object not template-argument-equivalent to introduced temporary — *end example*]
[9](#nontype-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1370)
[*Note [2](#nontype-note-2)*:
A [*string-literal*](lex.string#nt:string-literal "5.13.5String literals[lex.string]") ([[lex.string]](lex.string "5.13.5String literals")) is
not an acceptable [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") for a constant template parameter of non-class type[.](#nontype-9.sentence-1)
[*Example [3](#nontype-example-3)*: template<class T, T p> class X {/* ... */};
X<const char*, "Studebaker"> x; // error: string literal object as [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") X<const char*, "Knope" + 1> x2; // error: subobject of string literal object as [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")const char p[] = "Vivisectionist";
X<const char*, p> y; // OKstruct A {constexpr A(const char*) {}};
X<A, "Pyrophoricity"> z; // OK, [*string-literal*](lex.string#nt:string-literal "5.13.5String literals[lex.string]") is a constructor argument to A — *end example*]
— *end note*]
[10](#nontype-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1396)
[*Note [3](#nontype-note-3)*:
A temporary object
is not an acceptable[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") when the corresponding
template parameter
has reference type[.](#nontype-10.sentence-1)
[*Example [4](#nontype-example-4)*: template<const int& CRI> struct B { /* ... */ };
B<1> b1; // error: temporary would be required for template argumentint c = 1;
B<c> b2; // OKstruct X { int n; };struct Y { const int &r; };template<Y y> struct C { /* ... */ };
C<Y{X{1}.n}> c; // error: subobject of temporary object used to initialize// reference member of template parameter — *end example*]
— *end note*]
### [13.4.4](#template) Template template arguments [[temp.arg.template]](temp.arg.template)
[1](#template-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1424)
A[*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") for a template
template parameter
shall be the name of a template[.](#template-1.sentence-1)
For a [*type-tt-parameter*](temp.param#nt:type-tt-parameter "13.2Template parameters[temp.param]"),
the name shall denote a class template or alias template[.](#template-1.sentence-2)
For a [*variable-tt-parameter*](temp.param#nt:variable-tt-parameter "13.2Template parameters[temp.param]"),
the name shall denote a variable template[.](#template-1.sentence-3)
For a [*concept-tt-parameter*](temp.param#nt:concept-tt-parameter "13.2Template parameters[temp.param]"),
the name shall denote a concept[.](#template-1.sentence-4)
Only primary templates are considered when matching the template template
argument with the corresponding parameter; partial specializations are not
considered even if their parameter lists match that of the template template
parameter[.](#template-1.sentence-5)
[2](#template-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1441)
Any partial specializations ([[temp.spec.partial]](temp.spec.partial "13.7.6Partial specialization")) associated with the
primary template are considered when a
specialization based on the template template parameter is instantiated[.](#template-2.sentence-1)
If a specialization is not reachable from the point of instantiation,
and it would have been selected had it been reachable, the program is ill-formed,
no diagnostic required[.](#template-2.sentence-2)
[*Example [1](#template-example-1)*: template<class T> class A { // primary templateint x;};template<class T> class A<T*> { // partial specializationlong x;};template<template<class U> class V> class C { V<int> y;
V<int*> z;};
C<A> c; // V<int> within C<A> uses the primary template, so c.y.x has type int// V<int*> within C<A> uses the partial specialization, so c.z.x has type long — *end example*]
[3](#template-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1465)
A template template parameter P and
a [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") A are[*compatible*](#def:compatible,template_template_parameter_and_template_argument "13.4.4Template template arguments[temp.arg.template]") if
- [(3.1)](#template-3.1)
A denotes a class template or an alias template andP is a type template parameter,
- [(3.2)](#template-3.2)
A denotes a variable template andP is a variable template parameter, or
- [(3.3)](#template-3.3)
A denotes a concept andP is a concept template parameter[.](#template-3.sentence-1)
[4](#template-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1482)
A template [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") A matches a template
template parameter P whenA and P are compatible andP is at least as specialized as A, ignoring constraints
on A if P is unconstrained[.](#template-4.sentence-1)
If P contains a template parameter pack, then A also matches P if each of A's template parameters
matches the corresponding template parameter declared in the[*template-head*](temp.pre#nt:template-head "13.1Preamble[temp.pre]") of P[.](#template-4.sentence-2)
Two template parameters match if they are of the same kind,
for constant template parameters, their types are
equivalent ([[temp.over.link]](temp.over.link "13.7.7.2Function template overloading")), and for template template parameters,
each of their corresponding template parameters matches, recursively[.](#template-4.sentence-3)
When P's [*template-head*](temp.pre#nt:template-head "13.1Preamble[temp.pre]") contains a [*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]") that declares a template parameter
pack ([[temp.variadic]](temp.variadic "13.7.4Variadic templates")), the template parameter pack will match zero or more template
parameters or template parameter packs declared in the [*template-head*](temp.pre#nt:template-head "13.1Preamble[temp.pre]") ofA with the same type and form as the template parameter pack declared in P (ignoring whether those template parameters are template parameter packs)[.](#template-4.sentence-4)
[*Example [2](#template-example-2)*: template<class T> class A { /* ... */ };template<class T, class U = T> class B { /* ... */ };template<class ... Types> class C { /* ... */ };template<auto n> class D { /* ... */ };template<template<class> class P> class X { /* ... */ };template<template<class ...> class Q> class Y { /* ... */ };template<template<int> class R> class Z { /* ... */ };
X<A> xa; // OK X<B> xb; // OK X<C> xc; // OK Y<A> ya; // OK Y<B> yb; // OK Y<C> yc; // OK Z<D> zd; // OK — *end example*]
[*Example [3](#template-example-3)*: template <class T> struct eval;
template <template <class, class...> class TT, class T1, class... Rest>struct eval<TT<T1, Rest...>> { };
template <class T1> struct A;template <class T1, class T2> struct B;template <int N> struct C;template <class T1, int N> struct D;template <class T1, class T2, int N = 17> struct E;
eval<A<int>> eA; // OK, matches partial specialization of eval eval<B<int, float>> eB; // OK, matches partial specialization of eval eval<C<17>> eC; // error: C does not match TT in partial specialization eval<D<int, 17>> eD; // error: D does not match TT in partial specialization eval<E<int, float>> eE; // error: E does not match TT in partial specialization — *end example*]
[*Example [4](#template-example-4)*: template<typename T> concept C = requires (T t) { t.f(); };template<typename T> concept D = C<T> && requires (T t) { t.g(); };
template<template<C> class P> struct S { };
template<C> struct X { };template<D> struct Y { };template<typename T> struct Z { };
S<X> s1; // OK, X and P have equivalent constraints S<Y> s2; // error: P is not at least as specialized as Y S<Z> s3; // OK, P is at least as specialized as Z — *end example*]
[5](#template-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1559)
A template template parameter P is
at least as specialized as a template [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") A if, given the following rewrite to two function templates,
the function template corresponding to P is at least as specialized as
the function template corresponding to A according to the [partial ordering rules
for function templates](temp.func.order "13.7.7.3Partial ordering of function templates[temp.func.order]")[.](#template-5.sentence-1)
Given an invented class template X with the [*template-head*](temp.pre#nt:template-head "13.1Preamble[temp.pre]") of A (including default arguments
and [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]"), if any):
- [(5.1)](#template-5.1)
Each of the two function templates has the same template parameters
and [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") (if any),
respectively, as P or A[.](#template-5.1.sentence-1)
- [(5.2)](#template-5.2)
Each function template has a single function parameter
whose type is a specialization of X with template arguments corresponding to the template parameters
from the respective function template where,
for each [*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]") PP in the [*template-head*](temp.pre#nt:template-head "13.1Preamble[temp.pre]") of the function template,
a corresponding [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]") AA is formed[.](#template-5.2.sentence-1)
If PP declares a template parameter pack,
then AA is the pack expansion PP... ([[temp.variadic]](temp.variadic "13.7.4Variadic templates"));
otherwise, AA is an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") denoting PP[.](#template-5.2.sentence-2)
If the rewrite produces an invalid type,
then P is not at least as specialized as A[.](#template-5.sentence-3)