template-parameter: type-parameter parameter-declaration constrained-parameter
type-parameter: type-parameter-key ... identifier type-parameter-key identifier = type-id template-head type-parameter-key ... identifier template-head 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
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 }
struct A { auto operator<=>(A, A) = default; }; 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<double d> class X; // error template<double* pd> class Y; // OK template<double& rd> class Z; // OK— 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<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
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
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
template<class T1, class T2 = int> class A; template<class T1 = int, class T2> class A;
template<class T1 = int, class T2 = int> class A;— end 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
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 <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
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