17 Templates [temp]

17.3 Template arguments [temp.arg]

There are three forms of template-argument, corresponding to the three forms of template-parameter: type, non-type and template. The type and form of each template-argument specified in a template-id shall match the type and form specified for the corresponding parameter declared by the template in its template-parameter-list. When the parameter declared by the template is a template parameter pack, it will correspond to zero or more template-arguments. [Example:

template<class T> class Array {
  T* v;
  int sz;
  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]

In a template-argument, an ambiguity between a type-id and an expression is resolved to a type-id, regardless of the form of the corresponding template-parameter.137 [Example:

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]

The name of a template-argument shall be accessible at the point where it is used as a template-argument. [Note: If the name of the template-argument is accessible at the point where it is used as a template-argument, there is no further access restriction in the resulting instantiation where the corresponding template-parameter name is used. end note] [Example:

template<class T> class X {
  static T t;

class Y {
  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:

template <template <class TT> class T> class A {
  typename T<int>::S s;

template <class U> class B {
  struct S { /* ... */ };

A<B> b;             // ill-formed: A has no access to B​::​S

end example]

When template argument packs or default template-arguments are used, a template-argument list can be empty. In that case the empty <> brackets shall still be used as the template-argument-list. [Example:

template<class T = char> class String;
String<>* p;                    // OK: String<char>
String* q;                      // syntax error
template<class ... Elements> class Tuple;
Tuple<>* t;                     // OK: Elements is empty
Tuple* u;                       // syntax error

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:

template<class T> struct 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]

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 the template in a template-id is an overloaded function template, 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. If none of the function templates have matching template-parameters, the program is ill-formed.

When a simple-template-id does not name a function, a default template-argument is implicitly instantiated when the value of that default argument is needed. [Example:

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>*. end example]

A template-argument followed by an ellipsis is a pack expansion.

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.

17.3.1 Template type arguments [temp.arg.type]

A template-argument for a template-parameter which is a type shall be a type-id.


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: A template type argument may be an incomplete type. end note]

17.3.2 Template non-type arguments [temp.arg.nontype]

If the type of a template-parameter contains a placeholder type, the deduced parameter type is determined from the type of the template-argument by placeholder type deduction. If a deduced parameter type is not permitted for a template-parameter declaration ([temp.param]), the program is ill-formed.

A template-argument for a non-type template-parameter shall be a converted constant expression of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

[Note: If the template-argument represents a set of overloaded functions (or a pointer or member pointer to such), the matching function is selected from the set ([over.over]). end note]


template<const int* pci> struct X { /* ... */ };
int ai[10];
X<ai> xi;                       // array to pointer and qualification conversions

struct Y { /* ... */ };
template<const Y& b> struct Z { /* ... */ };
Y y;
Z<y> z;                         // no conversion, but note extra cv-qualification

template<int (&pa)[5]> struct W { /* ... */ };
int b[5];
W<b> w;                         // no conversion

void 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;                      // error: template parameter type cannot be double

end example]

[Note: A string literal is not an acceptable template-argument. [Example:

template<class T, const char* p> class X {
  /* ... */

X<int, "Studebaker"> x1;        // error: string literal as template-argument

const char p[] = "Vivisectionist";
X<int,p> x2;                    // OK

end example] end note]

[Note: The address of an array element or non-static data member is not an acceptable template-argument. [Example:

template<int* p> class X { };

int a[10];
struct S { int m; static int s; } s;

X<&a[2]> x3;                    // error: address of array element
X<&s.m> x4;                     // error: address of non-static member
X<&s.s> x5;                     // OK: address of static member
X<&S::s> x6;                    // OK: address of static member

end example] end note]

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

template<const int& CRI> struct B { /* ... */ };

B<1> b2;                        // error: temporary would be required for template argument

int c = 1;
B<c> b1;                        // OK

end example] end note]

17.3.3 Template template arguments [temp.arg.template]

A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression. When the template-argument names a class template, only primary class 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 associated with the primary class template or primary variable template are considered when a specialization based on the template template-parameter is instantiated. If a specialization is not visible at the point of instantiation, and it would have been selected had it been visible, the program is ill-formed, no diagnostic required. [Example:

template<class T> class A {     // primary template
  int x;
template<class T> class A<T*> { // partial specialization
  long 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-argument matches a template template-parameter P when P is at least as specialized as the template-argument A. If P contains a parameter pack, then A also matches P if each of A's template parameters matches the corresponding template parameter in the template-parameter-list of P. Two template parameters match if they are of the same kind (type, non-type, template), for non-type 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-parameter-list contains a template parameter pack, the template parameter pack will match zero or more template parameters or template parameter packs in the template-parameter-list of A with the same type and form as the template parameter pack in P (ignoring whether those template parameters are template parameter packs).


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]


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]

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 parameter list of A (including default arguments):

  • Each of the two function templates has the same template parameters, 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 parameter list of the function template, a corresponding template argument AA is formed. If PP declares a parameter pack, then AA is the pack expansion PP... ([temp.variadic]); otherwise, AA is the id-expression PP.

If the rewrite produces an invalid type, then P is not at least as specialized as A.