Namespaces
Variants

Template parameters

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

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:
  • a structural type (see below)
(since C++17)
(since C++20)
name - the name of the constant template parameter
default - the default template argument
1) A constant template parameter.
2) A constant template parameter with a default template argument.
3) A constant template parameter pack .


A structural type is one of the following types (optionally cv-qualified, the qualifiers are ignored):

(since C++11)
  • all base classes and non-static data members are public and non-mutable and
  • the types of all base classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.
(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 T denotes a static storage duration object of type const T , called a template parameter object , which is Template argument equivalence to the corresponding template argument after it has been converted to the type of the template parameter. No two template parameter objects are template-argument-equivalent.

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)

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
1) A type template parameter without a default.
template<class T>
class My_vector { /* ... */ };
2) A type template parameter with a default.
template<class T = void>
struct My_op_functor { /* ... */ };
3) A type template parameter pack .
template<typename... Ts>
class My_tuple { /* ... */ };
4) A constrained type template parameter without a default.
template<My_concept T>
class My_constrained_vector { /* ... */ };
5) A constrained type template parameter with a default.
template<My_concept T = void>
class My_constrained_op_functor { /* ... */ };
6) A constrained type template parameter pack .
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 P whose type-constraint is Q designating the concept C introduces a constraint-expression E according to the following rules:

  • if Q is C (without an argument list),
  • if P is not a parameter pack, E is simply C<P>
  • otherwise, P is a parameter pack, E is a fold-expression (C<P> && ...)
  • if Q is C<A1,A2...,AN> , then E is C<P,A1,A2,...AN> or (C<P,A1,A2,...AN> && ...) , respectively.
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)

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)
1) A template template parameter with an optional name.
2) A template template parameter with an optional name and a default.
3) A template template parameter pack with an optional name.


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;
};

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
};

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

(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)

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

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

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