[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.3 Names of template specializations [temp.names]") specified
in a [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") or
in a [*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice 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.1 Preamble [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.4 Variadic templates [temp.variadic]"), it will correspond to zero or more[*template-argument*](temp.names#nt:template-argument "13.3 Names 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.1 Preamble [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.1 Preamble [temp.pre]")[.](#general-2.sentence-1)

If the nth template parameter is
a template parameter pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic 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.3 Names of template specializations [temp.names]"),
an ambiguity between a[*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]") and an expression is resolved to a[*type-id*](dcl.name#nt:type-id "9.3.2 Type names [dcl.name]"),
regardless of the form of the corresponding[*template-parameter*](temp.param#nt:template-parameter "13.2 Template 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.3 Names 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.3 Names 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.3 Names 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.7 Destructors")) 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.3 Names 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.3 Names 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.3 Names of template specializations [temp.names]")*s* do not match the[*template-parameter*](temp.param#nt:template-parameter "13.2 Template 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.2 Template 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.3 Names of template specializations [temp.names]") or[*splice-specialization-specifier*](basic.splice#nt:splice-specialization-specifier "6.6 Splice specifiers [basic.splice]") does not designate a function,
a default [*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]") is[implicitly instantiated](temp.inst "13.9.2 Implicit 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.3 Names of template specializations [temp.names]") followed by an ellipsis is
a [pack expansion](temp.variadic#def:pack_expansion "13.7.4 Variadic 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.3 Names of template specializations [temp.names]") because the form of the[*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]") determines the allowable forms of the[*template-argument*](temp.names#nt:template-argument "13.3 Names 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.3 Names of template specializations [temp.names]") for a type template parameter
shall be a[*type-id*](dcl.name#nt:type-id "9.3.2 Type 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.1 General"))[.](#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.6 The constexpr and consteval specifiers"))[.](#nontype-1.sentence-1)

If T contains a placeholder type ([[dcl.spec.auto]](dcl.spec.auto "9.2.9.7 Placeholder type specifiers"))
or a placeholder for a deduced class type ([[dcl.type.class.deduct]](dcl.type.class.deduct "9.2.9.8 Deduced 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.3 Names of template specializations [temp.names]") or
(for a default template argument) an [*initializer-clause*](dcl.init.general#nt:initializer-clause "9.5.1 General [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.2 Template 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.1 General [dcl.init.general]"),A shall be a converted constant expression ([[expr.const]](expr.const "7.7 Constant 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.1 General [expr.prim.id.general]") v is termed a [*candidate initializer*](#def:candidate_initializer "13.4.3 Constant 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.2 Template 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.1 General [dcl.decl.general]") for the initialization would not be a constant expression
when interpreted as a [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") ([[expr.const]](expr.const "7.7 Constant expressions")), or

- [(4.3)](#nontype-4.3)

the initialization would cause P to not be template-argument-equivalent ([[temp.type]](temp.type "13.6 Type 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.7 Temporary objects")),

- [(6.2)](#nontype-6.2)

a string literal object ([[lex.string]](lex.string "5.13.5 String literals")),

- [(6.3)](#nontype-6.3)

the result of a typeid expression ([[expr.typeid]](expr.typeid "7.6.1.8 Type identification")),

- [(6.4)](#nontype-6.4)

a predefined __func__ variable ([[dcl.fct.def.general]](dcl.fct.def.general "9.6.1 General")), or

- [(6.5)](#nontype-6.5)

a subobject ([[intro.object]](intro.object "6.8.2 Object 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.5 String literals [lex.string]") ([[lex.string]](lex.string "5.13.5 String literals")) is
not an acceptable [*template-argument*](temp.names#nt:template-argument "13.3 Names 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.3 Names 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.3 Names 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.5 String 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.3 Names 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.3 Names 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.2 Template 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.2 Template 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.2 Template 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.6 Partial 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.3 Names of template specializations [temp.names]") A are[*compatible*](#def:compatible,template_template_parameter_and_template_argument "13.4.4 Template 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.3 Names 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.1 Preamble [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.2 Function 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.1 Preamble [temp.pre]") contains a [*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]") that declares a template parameter
pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic 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.1 Preamble [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.3 Names 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.3 Partial 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.1 Preamble [temp.pre]") of A (including default arguments
and [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [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.1 Preamble [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.2 Template parameters [temp.param]") PP in the [*template-head*](temp.pre#nt:template-head "13.1 Preamble [temp.pre]") of the function template,
a corresponding [*template-argument*](temp.names#nt:template-argument "13.3 Names 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.4 Variadic templates"));
otherwise, AA is an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [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)
