Template parameters
Every template is parameterized by one or more template parameters.
Each parameter in template-parameter-list (see template declaration syntax) belongs to one of the following categories:
- constant template parameter
- type template parameter
- template template parameter
Contents |
[edit] Constant template parameter
Also known as non-type template parameter (see below).
type name (optional) | (1) | ||||||||
type name (optional) = default
|
(2) | ||||||||
type ... name (optional)
|
(3) | (since C++11) | |||||||
type | - | one of the following types:
| ||||
name | - | the name of the constant template parameter | ||||
default | - | the default template argument |
A structural type is one of the following types (optionally cv-qualified, the qualifiers are ignored):
- lvalue reference type (to object or to function);
- an integral type;
- a pointer type (to object or to function);
- a pointer to member type (to member object or to member function);
- an enumeration type;
(since C++11) |
|
(since C++20) |
Array and function types may be written in a template declaration, but they are automatically replaced by pointer to object and pointer to function as appropriate.
When the name of a constant template parameter is used in an expression within the body of the class template, it is an unmodifiable prvalue unless its type was an lvalue reference type, or unless its type is a class type(since C++20).
A template parameter of the form class Foo is not an unnamed constant template parameter of type Foo
, even if otherwise class Foo is an elaborated type specifier and class Foo x; declares x to be of type Foo
.
An identifier that names a constant template parameter of class type struct A { friend bool operator==(const A&, const A&) = default; }; template<A a> void f() { &a; // OK const A& ra = a, &rb = a; // Both bound to the same template parameter object assert(&ra == &rb); // passes } |
(since C++20) |
[edit] Type template parameter
type-parameter-key name (optional) | (1) | ||||||||
type-parameter-key name (optional) = default
|
(2) | ||||||||
type-parameter-key ... name (optional)
|
(3) | (since C++11) | |||||||
type-constraint name (optional) | (4) | (since C++20) | |||||||
type-constraint name (optional) = default
|
(5) | (since C++20) | |||||||
type-constraint ... name (optional)
|
(6) | (since C++20) | |||||||
type-parameter-key | - | either typename or class . There is no difference between these keywords in a type template parameter declaration
|
type-constraint | - | either the name of a concept or the name of a concept followed by a list of template arguments (in angle brackets). Either way, the concept name may be optionally qualified |
name | - | the name of the type template parameter |
default | - | the default template argument |
template<class T> class My_vector { /* ... */ };
template<class T = void> struct My_op_functor { /* ... */ };
template<My_concept T> class My_constrained_vector { /* ... */ };
template<My_concept T = void> class My_constrained_op_functor { /* ... */ };
template<My_concept... Ts> class My_constrained_tuple { /* ... */ };
The name of the parameter is optional:
// Declarations of the templates shown above: template<class> class My_vector; template<class = void> struct My_op_functor; template<typename...> class My_tuple;
In the body of the template declaration, the name of a type parameter is a typedef-name which aliases the type supplied when the template is instantiated.
Each constrained parameter
template<typename T> concept C1 = true; template<typename... Ts> // variadic concept concept C2 = true; template<typename T, typename U> concept C3 = true; template<C1 T> struct s1; // constraint-expression is C1<T> template<C1... T> struct s2; // constraint-expression is (C1<T> && ...) template<C2... T> struct s3; // constraint-expression is (C2<T> && ...) template<C3<int> T> struct s4; // constraint-expression is C3<T, int> template<C3<int>... T> struct s5; // constraint-expression is (C3<T, int> && ...) |
(since C++20) |
[edit] Template template parameter
template < parameter-list > type-parameter-key name (optional)
|
(1) | ||||||||
template < parameter-list > type-parameter-key name (optional) = default
|
(2) | ||||||||
template < parameter-list > type-parameter-key ... name (optional)
|
(3) | (since C++11) | |||||||
type-parameter-key | - | class or typename (since C++17)
|
In the body of the template declaration, the name of this parameter is a template-name (and needs arguments to be instantiated).
template<typename T> class my_array {}; // two type template parameters and one template template parameter: template<typename K, typename V, template<typename> typename C = my_array> class Map { C<K> key; C<V> value; };
[edit] Name resolution for template parameters
The name of a template parameter is not allowed to be redeclared within its scope (including nested scopes). A template parameter is not allowed to have the same name as the template name.
template<class T, int N> class Y { int T; // error: template parameter redeclared void f() { char T; // error: template parameter redeclared } }; template<class X> class X; // error: template parameter redeclared
In the definition of a member of a class template that appears outside of the class template definition, the name of a member of the class template hides the name of a template parameter of any enclosing class templates, but not a template parameter of the member if the member is a class or function template.
template<class T> struct A { struct B {}; typedef void C; void f(); template<class U> void g(U); }; template<class B> void A<B>::f() { B b; // A's B, not the template parameter } template<class B> template<class C> void A<B>::g(C) { B b; // A's B, not the template parameter C c; // the template parameter C, not A's C }
In the definition of a member of a class template that appears outside of the namespace containing the class template definition, the name of a template parameter hides the name of a member of this namespace.
namespace N { class C {}; template<class T> class B { void f(T); }; } template<class C> void N::B<C>::f(C) { C b; // C is the template parameter, not N::C }
In the definition of a class template or in the definition of a member of such a template that appears outside of the template definition, for each non-dependent base class, if the name of the base class or the name of a member of the base class is the same as the name of a template parameter, the base class name or member name hides the template parameter name.
struct A { struct B {}; int C; int Y; }; template<class B, class C> struct X : A { B b; // A's B C b; // error: A's C isn't a type name };
[edit] Default template arguments
Default template arguments are specified in the parameter lists after the = sign. Defaults can be specified for any kind of template parameter (type, constant, or template), but not to parameter packs(since C++11).
If the default is specified for a template parameter of a primary class template, primary variable template,(since C++14) or alias template, each subsequent template parameter must have a default argument, except the very last one may be a template parameter pack(since C++11). In a function template, there are no restrictions on the parameters that follow a default, and a parameter pack may be followed by more type parameters only if they have defaults or can be deduced from the function arguments(since C++11).
Default parameters are not allowed
- in the out-of-class definition of a member of a class template (they have to be provided in the declaration inside the class body). Note that member templates of non-template classes can use default parameters in their out-of-class definitions (see GCC bug 53856)
- in friend class template declarations
|
(until C++11) |
On a friend function template declaration, default template arguments are allowed only if the declaration is a definition, and no other declarations of this function appear in this translation unit. |
(since C++11) |
Default template arguments that appear in the declarations are merged similarly to default function arguments:
template<typename T1, typename T2 = int> class A; template<typename T1 = int, typename T2> class A; // the above is the same as the following: template<typename T1 = int, typename T2 = int> class A;
But the same parameter cannot be given default arguments twice in the same scope:
template<typename T = int> class X; template<typename T = int> class X {}; // error
When parsing a default template argument for a constant template parameter, the first non-nested > is taken as the end of the template parameter list rather than a greater-than operator:
template<int i = 3 > 4> // syntax error class X { /* ... */ }; template<int i = (3 > 4)> // OK class Y { /* ... */ };
The template parameter lists of template template parameters can have their own default arguments, which are only in effect where the template template parameter itself is in scope:
// class template, with a type template parameter with a default template<typename T = float> struct B {}; // template template parameter T has a parameter list, which // consists of one type template parameter with a default template<template<typename = float> typename T> struct A { void f(); void g(); }; // out-of-body member function template definitions template<template<typename TT> class T> void A<T>::f() { T<> t; // error: TT has no default in scope } template<template<typename TT = char> class T> void A<T>::g() { T<> t; // OK: t is T<char> }
Member access for the names used in a default template parameter is checked at the declaration, not at the point of use:
class B {}; template<typename T> class C { protected: typedef T TT; }; template<typename U, typename V = typename U::TT> class D: public U {}; D<C<B>>* d; // error: C::TT is protected
The default template argument is implicitly instantiated when the value of that default argument is needed, except if the template is used to name a function: template<typename T, typename U = int> struct S {}; S<bool>* p; // The default argument for U is instantiated at this point // the type of p is S<bool, int>* |
(since C++14) |
[edit] Notes
Before C++26, constant template parameter were called non-type template parameter in the standard wording. The terminology was changed by P2841R6 / PR#7587.
In template parameters, type constraints could be used for both type and constant parameters, depending on whether auto is present. template<typename> concept C = true; template<C, // type parameter C auto // constant parameter > struct S{}; S<int, 0> s;
|
(since C++20) |
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_nontype_template_parameter_auto |
201606L |
(C++17) | Declaring constant template parameters with auto |
__cpp_nontype_template_args |
201411L |
(C++17) | Allow constant evaluation for all constant template arguments |
201911L |
(C++20) | Class types and floating-point types in constant template parameters |
[edit] Examples
#include <array> #include <iostream> #include <numeric> // simple constant template parameter template<int N> struct S { int a[N]; }; template<const char*> struct S2 {}; // complicated constant example template < char c, // integral type int (&ra)[5], // lvalue reference to object (of array type) int (*pf)(int), // pointer to function int (S<10>::*a)[10] // pointer to member object (of type int[10]) > struct Complicated { // calls the function selected at compile time // and stores the result in the array selected at compile time void foo(char base) { ra[4] = pf(c - base); } }; // S2<"fail"> s2; // error: string literal cannot be used char okay[] = "okay"; // static object with linkage // S2<&okay[0]> s3; // error: array element has no linkage S2<okay> s4; // works int a[5]; int f(int n) { return n; } // C++20: NTTP can be a literal class type template<std::array arr> constexpr auto sum() { return std::accumulate(arr.cbegin(), arr.cend(), 0); } // C++20: class template arguments are deduced at the call site static_assert(sum<std::array<double, 8>{3, 1, 4, 1, 5, 9, 2, 6}>() == 31.0); // C++20: NTTP argument deduction and CTAD static_assert(sum<std::array{2, 7, 1, 8, 2, 8}>() == 28); int main() { S<10> s; // s.a is an array of 10 int s.a[9] = 4; Complicated<'2', a, f, &S<10>::a> c; c.foo('0'); std::cout << s.a[9] << a[4] << '\n'; }
Output:
42
This section is incomplete Reason: more examples |
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 184 | C++98 | whether the template parameters of template template parameters are allowed to have default arguments is unspecified |
specification added |
CWG 1922 | C++98 | it was unclear whether a class template whose name is an injected-class-name can use the default arguments in prior declarations |
allowed |
CWG 2032 | C++14 | for variable templates, there was no restriction on the template parameters after a template parameter with a default argument |
apply the same restriction as on class templates and alias templates |
CWG 2542 | C++20 | it was unclear whether the closure type is structural | it is not structural |
CWG 2845 | C++20 | the closure type was not structural | it is structural if capture-less |