17 Templates [temp]

17.1 Template parameters [temp.param]

The syntax for template-parameters is:
template-parameter:
	type-parameter
	parameter-declaration
	constrained-parameter
type-parameter:
	type-parameter-key ... identifier
	type-parameter-key identifier = type-id
	template < template-parameter-list > type-parameter-key ... identifier
	template < template-parameter-list > type-parameter-key identifier = id-expression
type-parameter-key:
	class
	typename
constrained-parameter:
	qualified-concept-name ... identifier
	qualified-concept-name identifier default-template-argument
qualified-concept-name:
	nested-name-specifier concept-name
	nested-name-specifier partial-concept-id
partial-concept-id:
	concept-name < template-argument-list >
default-template-argument:
	= type-id
	= id-expression
	= initializer-clause
[Note
:
The > token following the template-parameter-list of a type-parameter may be the product of replacing a >> token by two consecutive > tokens ([temp.names]).
end note
]
There is no semantic difference between class and typename in a type-parameter-key.
typename followed by an unqualified-id names a template type parameter.
typename followed by a qualified-id denotes the type in a non-type135 parameter-declaration.
[Example
:
class T { /* ... */ };
int i;

template<class T, T i> void f(T t) {
  T t1 = i;         // template-parameters T and i
  ::T t2 = ::i;     // global namespace members T and i
}
Here, the template f has a type-parameter called T, rather than an unnamed non-type template-parameter of class T.
end example
]
A storage class shall not be specified in a template-parameter declaration.
Types shall not be defined in a template-parameter declaration.
A type-parameter whose identifier does not follow an ellipsis defines its identifier to be a typedef-name (if declared without template) or template-name (if declared with template) in the scope of the template declaration.
[Note
:
A template argument may be a class template or alias template.
For example,
template<class T> class myarray { /* ... */ };

template<class K, class V, template<class T> class C = myarray>
class Map {
  C<K> key;
  C<V> value;
};
end note
]
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
  • integral or enumeration type,
  • pointer to object or pointer to function,
  • lvalue reference to object or lvalue reference to function,
  • pointer to member,
  • std​::​nullptr_­t, or
  • a type that contains a placeholder type.
[Note
:
Other types are disallowed either explicitly below or implicitly by the rules governing the form of template-arguments ([temp.arg]).
end note
]
The top-level cv-qualifiers on the template-parameter are ignored when determining its type.
A non-type non-reference template-parameter is a prvalue.
It shall not be assigned to or in any other way have its value changed.
A non-type non-reference template-parameter cannot have its address taken.
When a non-type non-reference template-parameter is used as an initializer for a reference, a temporary is always used.
[Example
:
template<const X& x, int i> void f() {
  i++;                          // error: change of template-parameter value

  &x;                           // OK
  &i;                           // error: address of non-reference template-parameter

  int& ri = i;                  // error: non-const reference bound to temporary
  const int& cri = i;           // OK: const reference bound to temporary
}
end example
]
A non-type template-parameter shall not be declared to have floating-point, class, or void type.
[Example
:
template<double d> class X;     // error
template<double* pd> class Y;   // OK
template<double& rd> class Z;   // OK
end example
]
A non-type template-parameter of type “array of T” or of function type T is adjusted to be of type “pointer to T.
[Example
:
template<int* a>   struct R { /* ... */ };
template<int b[5]> struct S { /* ... */ };
int p;
R<&p> w;                        // OK
S<&p> x;                        // OK due to parameter adjustment
int v[5];
R<v> y;                         // OK due to implicit argument conversion
S<v> z;                         // OK due to both adjustment and conversion
end example
]
A partial-concept-id is a concept-name followed by a sequence of template-arguments.
These template arguments are used to form a constraint-expression as described below.
A constrained-parameter declares a template parameter whose kind (type, non-type, template) and type match that of the prototype parameter ([temp.concept]) of the concept designated by the qualified-concept-name in the constrained-parameter.
Let X be the prototype parameter of the designated concept.
The declared template parameter is determined by the kind of X (type, non-type, template) and the optional ellipsis in the constrained-parameter as follows.
[Example
:
template<typename T> concept C1 = true;
template<template<typename> class X> concept C2 = true;
template<int N> concept C3 = true;
template<typename... Ts> concept C4 = true;
template<char... Cs> concept C5 = true;

template<C1 T> void f1();       // OK, T is a type template-parameter
template<C2 X> void f2();       // OK, X is a template with one type-parameter
template<C3 N> void f3();       // OK, N has type int
template<C4... Ts> void f4();   // OK, Ts is a template parameter pack of types
template<C4 T> void f5();       // OK, T is a type template-parameter
template<C5... Cs> void f6();   // OK, Cs is a template parameter pack of chars
end example
]
The expression is derived from the qualified-concept-name Q in the constrained-parameter, its designated concept C, and the declared template parameter P.
E is the introduced constraint-expression.
[Example
:
template<typename T> concept C1 = true;
template<typename... Ts> concept C2 = true;
template<typename T, typename U> concept C3 = true;

template<C1 T> struct s1;       // associates C1<T>
template<C1... T> struct s2;    // associates (C1<T> && ...)
template<C2... T> struct s3;    // associates C2<T...>
template<C3<int> T> struct s4;  // associates C3<T, int>
end example
]
A default template-argument may be specified for any kind of template-parameter (type, non-type, template) that is not a template parameter pack.
A default template-argument may be specified in a template declaration.
A default template-argument shall not be specified in the template-parameter-lists of the definition of a member of a class template that appears outside of the member's class.
A default template-argument shall not be specified in a friend class template declaration.
If a friend function template declaration specifies a default template-argument, that declaration shall be a definition and shall be the only declaration of the function template in the translation unit.
The default template-argument of a constrained-parameter shall match the kind (type, non-type, template) of the declared template parameter.
[Example
:
template<typename T> concept C1 = true;
template<int N> concept C2 = true;
template<template<typename> class X> concept C3 = true;

template<typename T> struct S0;

template<C1 T = int> struct S1; // OK
template<C2 N = 0> struct S2;   // OK
template<C3 X = S0> struct S3;  // OK
template<C1 T = 0> struct S4;   // error: default argument is not a type
end example
]
The set of default template-arguments available for use is obtained by merging the default arguments from all prior declarations of the template in the same way default function arguments are ([dcl.fct.default]).
[Example
:
template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;
end example
]
If a template-parameter of a class template, variable template, or alias template has a default template-argument, each subsequent template-parameter shall either have a default template-argument supplied or be a template parameter pack.
If a template-parameter of a primary class template, primary variable template, or alias template is a template parameter pack, it shall be the last template-parameter.
A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list ([dcl.fct]) of the function template or has a default argument ([temp.deduct]).
A template parameter of a deduction guide template ([temp.deduct.guide]) that does not have a default argument shall be deducible from the parameter-type-list of the deduction guide template.
[Example
:
template<class T1 = int, class T2> class B;     // error

// U can be neither deduced from the parameter-type-list nor specified
template<class... T, class... U> void f() { }   // error
template<class... T, class U> void g() { }      // error
end example
]
A template-parameter shall not be given default arguments by two different declarations in the same scope.
[Example
:
template<class T = int> class X;
template<class T = int> class X { /* ... */ };  // error
end example
]
When parsing a default template-argument for a non-type template-parameter, the first non-nested > is taken as the end of the template-parameter-list rather than a greater-than operator.
[Example
:
template<int i = 3 > 4 >        // syntax error
class X { /* ... */ };

template<int i = (3 > 4) >      // OK
class Y { /* ... */ };
end example
]
A template-parameter of a template template-parameter is permitted to have a default template-argument.
When such default arguments are specified, they apply to the template template-parameter in the scope of the template template-parameter.
[Example
:
template <class T = float> struct B {};
template <template <class TT = float> class T> struct A {
  inline void f();
  inline void g();
};
template <template <class TT> class T> void A<T>::f() {
  T<> t;            // error: TT has no default template argument
}
template <template <class TT = char> class T> void A<T>::g() {
  T<> t;            // OK, T<char>
}
end example
]
If a template-parameter is a type-parameter with an ellipsis prior to its optional identifier or is a parameter-declaration that declares a parameter pack ([dcl.fct]), then the template-parameter is a template parameter pack.
A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded parameter packs is a pack expansion.
Similarly, a template parameter pack that is a type-parameter with a template-parameter-list containing one or more unexpanded parameter packs is a pack expansion.
A template parameter pack that is a pack expansion shall not expand a parameter pack declared in the same template-parameter-list.
[Example
:
template <class... Types>                       // Types is a template type parameter pack
   class Tuple;                                 // but not a pack expansion

template <class T, int... Dims>                 // Dims is a non-type template parameter pack
   struct multi_array;                          // but not a pack expansion

template <class... T>
  struct value_holder {
    template <T... Values> struct apply { };    // Values is a non-type template parameter pack
  };                                            // and a pack expansion

template <class... T, T... Values>              // error: Values expands template type parameter
  struct static_array;                          // pack T within the same template parameter list
end example
]
Since template template-parameters and template template-arguments are treated as types for descriptive purposes, the terms non-type parameter and non-type argument are used to refer to non-type, non-template parameters and arguments.