template-parameter: type-parameter parameter-declaration
type-parameter: type-parameter-key ... identifier type-parameter-key identifier = type-id type-constraint ... identifier type-constraint identifier = type-id template-head type-parameter-key ... identifier template-head type-parameter-key identifier = id-expression
type-parameter-key: class typename
type-constraint: nested-name-specifier concept-name nested-name-specifier concept-name < template-argument-list >
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 }
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> template<C3<int>... T> struct s5; // associates (C3<T, int> && ...)— end example
using X = int; struct A {}; template<const X& x, int i, A a> void f() { i++; // error: change of template-parameter value &x; // OK &i; // error: address of non-reference template-parameter &a; // OK int& ri = i; // error: non-const reference bound to temporary const int& cri = i; // OK: const reference bound to temporary const A& ra = a; // OK: const reference bound to a template parameter object }— end 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
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;
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
template<class T = int> class X; template<class T = int> class X { /* ... */ }; // error— end example
template<int i = 3 > 4 > // syntax error class X { /* ... */ }; template<int i = (3 > 4) > // OK class Y { /* ... */ };— end example
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
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