The template argument list of a template-head is
a template argument list in which the nth template argument
has the value of
the nth template parameter of the template-head.
If the nth template parameter is
a template parameter pack ([temp.variadic]),
the nth template argument is a pack expansion
whose pattern is the name of the template parameter pack.
Names used in a template-argument
are subject to access control where they appear.
Because a template parameter is not a class member,
no access control applies where the template parameter is used.
— end note]
[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.
[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]
An explicit destructor call ([class.dtor]) for an object that has a type
that is a class template specialization may explicitly specify the
template-arguments.
When name lookup for the component name of a
template-id
finds an overload set, both non-template functions in the overload
set and function templates in the overload set for
which the
template-arguments
do not match the
template-parameters
are ignored.
A template argument E for
a constant template parameter with declared type T
shall be such that the invented declaration
T x =E ;
satisfies the semantic constraints for the definition of
a constexpr variable with static storage duration ([dcl.constexpr]).
If T contains a placeholder type ([dcl.spec.auto])
or a placeholder for a deduced class type ([dcl.type.class.deduct]),
the type of the parameter is deduced from the above declaration.
The value of a constant template parameter P
of (possibly deduced) type T
is determined from its template argument A as follows.
If T is not a class type and
A is not a braced-init-list,
A shall be a converted constant expression ([expr.const])
of type T; the value of P is A (as converted).
If T is a class type,
a template parameter object ([temp.param]) exists
that is constructed so as to be template-argument-equivalent to v;
P denotes that template parameter object.
P is copy-initialized from an unspecified candidate initializer
that is template-argument-equivalent to v.
If, for the initialization from any candidate initializer,
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):
[Example 1: template<int& r>class A{};
externint x;
A<x> a; / OKvoid f(int p){constexprint& r = p; / OK
A<r> a; / error: a static constexpr int& variable cannot be initialized to refer to p here} — end example]
[Example 2: template<constint* 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]
A temporary object
is not an acceptable
template-argument
when the corresponding
template parameter
has reference type.
[Example 4: template<constint& 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 {constint&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]
A
template-argument
for a template
template parameter
shall be the name of a template.
For a type-tt-parameter,
the name shall denote a class template, alias template, or
type template template parameter.
For a variable-tt-parameter,
the name shall denote a variable template or
variable template template parameter.
For a concept-tt-parameter,
the name shall denote a concept or
concept template parameter.
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.
Any partial specializations ([temp.spec.partial]) associated with the
primary template are considered when a
specialization based on the template template parameter is instantiated.
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.
[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]
A template template-argumentA matches a template
template parameter P when
A and P are compatible and
P is at least as specialized as A, ignoring constraints
on A if P is unconstrained.
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 of P.
Two template parameters match if they are of the same kind,
for constant template parameters, their types are
equivalent ([temp.over.link]), and for template template parameters,
each of their corresponding template parameters matches, recursively.
When P's template-head contains a template-parameter
that declares a template parameter
pack ([temp.variadic]), the template parameter pack will match zero or more template
parameters or template parameter packs declared in the template-head of
A with the same type and form as the template parameter pack declared in P
(ignoring whether those template parameters are template parameter packs).
[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<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<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]
A template template parameter P is
at least as specialized as a template template-argumentA
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.
Given an invented class template X
with the template-head of A (including default arguments
and requires-clause, if any):
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-parameterPP
in the template-head of the function template,
a corresponding template-argumentAA is formed.
If PP declares a template parameter pack,
then AA is the pack expansion PP.. ([temp.variadic]);
otherwise, AA is an id-expression denoting PP.
If the rewrite produces an invalid type,
then P is not at least as specialized as A.