[temp.arg]

13 Templates [temp]

13.4 Template arguments [temp.arg]


13.4.1 General [temp.arg.general]

13.4.2 Type template arguments [temp.arg.type]

13.4.3 Constant template arguments [temp.arg.nontype]

13.4.4 Template template arguments [temp.arg.template]


13.4.1 General [temp.arg.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; Array<dcomplex> v2(30); Array<dcomplex> v3(40); void bar() { v1[3] = 7; v2[3] = v3.elem(4) = dcomplex(7,8); } — end example]

The template argument list of a template-head is a template argument list in which the template argument has the value of the template parameter of the template-head.

If the template parameter is a template parameter pack ([temp.variadic]), the template argument is a pack expansion whose pattern is the name of the template parameter pack.

If a template-argument A matches the form template-argument-name, it is interpreted as such; the identifier is looked up and its meaning is determined as follows:

  • If lookup finds an injected-class-name ([temp.local]), then:

    • When A is for a type template template parameter, A denotes the corresponding class template.

  • Otherwise, if lookup finds a template, A denotes that template.

  • Otherwise, if lookup finds a type alias or a type, A denotes the underlying type and is interpreted as a type-id.

  • Otherwise, A is interpreted as an expression.

[Example 2: template<class T> void f(); template<int I> void f(); void g() { f<int()>(); } — end example]

[Note 1:

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; }; X<Y::S> y; — 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; — end example]

When template argument packs or default template arguments are used, a template-argument list can be empty.

[Example 5: template<class T = char> class String; String<>* p; String* q; template<class ... Elements> class Tuple; Tuple<>* t; Tuple* u; — 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.

[Example 6: template<class T> struct A { ~A(); }; void f(A<int>* p, A<int>* q) { p->A<int>::~A(); q->A<int>::~A<int>(); } — end example]

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.

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.

[Note 2:

If none of the function templates have matching template-parameters, the program is ill-formed.

— end note]

[Example 7: template<typename T, typename U = int> struct S { }; S<bool>* p;

The default argument for U is instantiated to form the type S<bool, int>*.

— end example]

13.4.2 Type template arguments [temp.arg.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; X<A*> x2; X<B> x3; f(e1); f(unnamed_obj); f(b); } — end example]

13.4.3 Constant template arguments [temp.arg.nontype]

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.

If the parameter type thus deduced is not permitted for a constant template parameter ([temp.param]), the program is ill-formed.

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).

Otherwise, a temporary variable constexpr T v = A; is introduced.

The lifetime of v ends immediately after initializing it and any template parameter object (see below).

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,

  • the initialization would be ill-formed, or
  • the full-expression of an invented init-declarator for the initialization would not be a constant expression when interpreted as a constant-expression ([expr.const]), or
  • the initialization would cause P to not be template-argument-equivalent ([temp.type]) to v,

the program is ill-formed.

Otherwise, the value of P is that of v.

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{}; extern int x; A<x> a; void f(int p) { constexpr int& r = p; A<r> a; } — end example]

[Example 2: template<const int* pci> struct X { }; int ai[10]; X<ai> xi; struct Y { }; template<const Y& b> struct Z { }; Y y; Z<y> z; template<int (&pa)[5]> struct W { }; int b[5]; W<b> w; void f(char); void f(int); template<void (*pf)(int)> struct A { }; A<&f> a; template<auto n> struct B { }; B<5> b1; B<'a'> b2; B<2.5> b3; B<void(0)> b4; template<int i> struct C { }; C<{ 42 }> c1; struct J1 { J1 *self = this; }; B<J1{}> j1; struct J2 { J2 *self = this; constexpr J2() {} constexpr J2(const J2&) {} }; B<J2{}> j2; — end example]

[Note 2:

[Example 3: template<class T, T p> class X { }; X<const char*, "Studebaker"> x; X<const char*, "Knope" + 1> x2; const char p[] = "Vivisectionist"; X<const char*, p> y; struct A { constexpr A(const char*) {} }; X<A, "Pyrophoricity"> z; — end example]

— end note]

[Note 3:

A temporary object is not an acceptable template-argument when the corresponding template parameter has reference type.

[Example 4: template<const int& CRI> struct B { }; B<1> b1; int c = 1; B<c> b2; struct X { int n; }; struct Y { const int &r; }; template<Y y> struct C { }; C<Y{X{1}.n}> c; — end example]

— end note]

13.4.4 Template template arguments [temp.arg.template]

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 { int x; }; template<class T> class A<T*> { long x; }; template<template<class U> class V> class C { V<int> y; V<int*> z; }; C<A> c; — end example]

A template template parameter P and a template-argument A are compatible if

  • A denotes a class template or an alias template and P is a type template template parameter,
  • A denotes a variable template and P is a variable template template parameter, or
  • A denotes a concept and P is a concept template parameter.

A template template-argument A 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; X<B> xb; X<C> xc; Y<A> ya; Y<B> yb; Y<C> yc; Z<D> zd; — 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; eval<B<int, float>> eB; eval<C<17>> eC; eval<D<int, 17>> eD; eval<E<int, float>> eE; — 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; S<Y> s2; S<Z> s3; — end example]

A template template parameter P is at least as specialized as a template template-argument 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.

Given an invented class template X with the template-head of A (including default arguments and requires-clause, if any):

  • Each of the two function templates has the same template parameters and requires-clause (if any), respectively, as P or A.

  • 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 PP in the template-head of the function template, a corresponding template-argument AA 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.