The syntax for template-parameters is:
template-parameter: type-parameter parameter-declaration
type-parameter: class ...opt identifieropt class identifieropt = type-id typename ...opt identifieropt typename identifieropt = type-id template < template-parameter-list > class ...opt identifieropt template < template-parameter-list > class identifieropt = id-expression
[ 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 template-parameter. typename followed by an unqualified-id names a template type parameter. typename followed by a qualified-id denotes the type in a non-type 137 parameter-declaration. A storage class shall not be specified in a template-parameter declaration. Types shall not be defined in a template-parameter declaration. [ Note: A template parameter may be a class 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 type-parameter whose identifier does not follow an ellipsis defines its identifier to be a typedef-name (if declared with class or typename) or template-name (if declared with template) in the scope of the template declaration. [ Note: Because of the name lookup rules, a template-parameter that could be interpreted as either a non-type template-parameter or a type-parameter (because its identifier is the name of an already existing class) is taken as a type-parameter. For 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 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.
[ 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 “function returning T” is adjusted to be of type “pointer to T” or “pointer to function returning T”, respectively. [ 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 default template-argument is a template-argument ([temp.arg]) specified after = in a template-parameter. A default template-argument may be specified for any kind of template-parameter (type, non-type, template) that is not a template parameter pack ([temp.variadic]). 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 set of default template-arguments available for use with a template declaration or definition is obtained by merging the default arguments from the definition (if in scope) and all declarations in scope 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 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 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 of the function template or has a default argument ([temp.deduct]). [ 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 ([temp.variadic]). 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> class Tuple; // Types is a template type parameter pack // but not a pack expansion template <class T, int... Dims> struct multi_array; // Dims is a non-type template parameter pack // 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> struct static_array;// error: Values expands template type parameter // 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.