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 | ||||||||||||||||
| ||||||||||||||||
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 | ||||||||||||||||
In order for a template to be instantiated, everytemplate parameter must be replaced by a corresponding template argument. The arguments are either explicitly provided, deduced or defaulted.
Each parameter intemplate-parameter-list (seetemplate identifier syntax) belongs to one of the following categories:
Contents |
Also known asnon-type template arguments (seebelow).
The template argument that can be used with a constant template parameter can be anymanifestly constant-evaluated expression. | (until C++11) |
The template argument that can be used with a constant template parameter can be anyinitializer clause. If the initializer clause is an expression, it must bemanifestly constant-evaluated. | (since C++11) |
Given thetype of theconstant template parameter declaration asT
and the template argument provided for the parameter asE.
The invented declarationT x= E; must satisfy the semantic constraints for the definition of aconstexpr variable withstatic storage duration. | (since C++20) |
If If a deduced parameter type is not astructural type, the program is ill-formed. For constant template parameter packs whose type uses a placeholder type, the type is independently deduced for each template argument and need not match. | (since C++17) |
template<auto n>struct B{/* ... */}; B<5> b1;// OK: constant template parameter type is intB<'a'> b2;// OK: constant template parameter type is charB<2.5> b3;// error (until C++20): constant template parameter type cannot be double // C++20 deduced class type placeholder, class template arguments are deduced at the// call sitetemplate<std::array arr>void f(); f<std::array<double,8>{}>(); template<auto...>struct C{}; C<'C',0,2L, nullptr> x;// OK
The value of a constant template parameterP of (possibly deduced)(since C++17) typeT
is determined from its template argumentA as follows:
| (until C++11) |
| (since C++11) (until C++20) |
| (since C++20) |
template<int i>struct C{/* ... */}; C<{42}> c1;// OK template<auto n>struct B{/* ... */}; struct J1{ J1* self= this;}; B<J1{}> j1;// error: initialization of the template parameter object// is not a constant expression struct J2{ J2*self= this;constexpr J2(){}constexpr J2(const J2&){}}; B<J2{}> j2;// error: the template parameter object is not// template-argument-equivalent to introduced temporary
The following limitations apply when instantiating templates that have constant template parameters:
In particular, this implies that string literals, addresses of array elements, and addresses of non-static members cannot be used as template arguments to instantiate templates whose corresponding constant template parameters are pointers to objects. | (until C++17) |
constant template parameters of reference or pointer typeand non-static data members of reference or pointer type in a constant template parameter of class type and its subobjects(since C++20) cannot refer to/be the address of
| (since C++17) |
template<constint* pci>struct X{}; int ai[10];X<ai> xi;// OK: array to pointer conversion and cv-qualification conversion struct Y{}; template<const Y& b>struct Z{}; Y y;Z<y> z;// OK: no conversion template<int(&pa)[5]>struct W{}; int b[5];W<b> w;// OK: no conversion void f(char);void f(int); template<void(*pf)(int)>struct A{}; A<&f> a;// OK: overload resolution selects f(int)
template<class T,constchar* p>class X{}; X<int,"Studebaker"> x1;// error: string literal as template-argument template<int* p>class X{}; int a[10]; struct S{int m;staticint s;} s; X<&a[2]> x3;// error (until C++20): address of array elementX<&s.m> x4;// error (until C++20): address of non-static memberX<&s.s> x5;// OK: address of static memberX<&S::s> x6;// OK: address of static member template<constint& CRI>struct B{}; B<1> b2;// error: temporary would be required for template argumentint c=1;B<c> b1;// OK
A template argument for a type template parameter must be atype-id, which may name an incomplete type:
template<typename T>class X{};// class template struct A;// incomplete typetypedefstruct{} B;// type alias to an unnamed type int main(){ X<A> x1;// OK: 'A' names a type X<A*> x2;// OK: 'A*' names a type X<B> x3;// OK: 'B' names a type}
A template argument for a template template parameter must be anid-expression which names a class template or a template alias.
When the argument is a class template, only the primary template is considered when matching the parameter. The partial specializations, if any, are only considered when a specialization based on this template template parameter happens to be instantiated.
template<typename T>// primary templateclass A{int x;}; template<typename T>// partial specializationclass A<T*>{long x;}; // class template with a template template parameter Vtemplate<template<typename>class V>class C{ V<int> y;// uses the primary template V<int*> z;// uses the partial specialization}; C<A> c;// c.y.x has type int, c.z.x has type long
To match a template template argumentA
to a template template parameterP
,P
must beat least as specialized asA
(see below). IfP
's parameter list includes aparameter pack, zero or more template parameters (or parameter packs) fromA
's template parameter list are matched by it.(since C++11)
Formally, a template template-parameterP
isat least as specialized as a template template argumentA
if, given the following rewrite to two function templates, the function template corresponding toP
is at least as specialized as the function template corresponding toA
according to the partial ordering rules forfunction templates. Given an invented class templateX
with the template parameter list ofA
(including default arguments):
P
orA
.X
with template arguments corresponding to the template parameters from the respective function template where, for each template parameterPP
in the template parameter list of the function template, a corresponding template argumentAA
is formed. IfPP
declares a parameter pack, thenAA
is the pack expansionPP...
; otherwise,(since C++11)AA
is the id-expressionPP
.If the rewrite produces an invalid type, thenP
is not at least as specialized asA
.
template<typename T>struct eval;// primary template template<template<typename,typename...>class TT,typename T1,typename...Rest>struct eval<TT<T1, Rest...>>{};// partial specialization of eval template<typename T1>struct A;template<typename T1,typename T2>struct B;template<int N>struct C;template<typename T1,int N>struct D;template<typename T1,typename T2,int N=17>struct E; eval<A<int>> eA;// OK: matches partial specialization of evaleval<B<int,float>> eB;// OK: matches partial specialization of evaleval<C<17>> eC;// error: C does not match TT in partial specialization// because TT's first parameter is a// type template parameter, while 17 does not name a typeeval<D<int,17>> eD;// error: D does not match TT in partial specialization// because TT's second parameter is a// type parameter pack, while 17 does not name a typeeval<E<int,float>> eE;// error: E does not match TT in partial specialization// because E's third (default) parameter is a constant
Before the adoption ofP0522R0, each of the template parameters ofA
must match corresponding template parameters ofP
exactly. This hinders many reasonable template argument from being accepted.
Although it was pointed out very early (CWG#150), by the time it was resolved, the changes were applied to the C++17 working paper and the resolution became a de facto C++17 feature. Many compilers disable it by default:
template<class T>class A{/* ... */};template<class T,class U= T>class B{/* ... */};template<class...Types>class C{/* ... */}; template<template<class>class P>class X{/* ... */};X<A> xa;// OKX<B> xb;// OK after P0522R0// Error earlier: not an exact matchX<C> xc;// OK after P0522R0// Error earlier: not an exact match template<template<class...>class Q>class Y{/* ... */};Y<A> ya;// OKY<B> yb;// OKY<C> yc;// OK template<auto n>class D{/* ... */};// note: C++17template<template<int>class R>class Z{/* ... */};Z<D> zd;// OK after P0522R0: the template parameter// is more specialized than the template argument template<int>struct SI{/* ... */};template<template<auto>class>void FA();// note: C++17FA<SI>();// Error
Template argument equivalence is used to determine whether twotemplate identifiers are same.
Two values aretemplate-argument-equivalent if they are of the same type and any of the following conditions is satisfied:
| (since C++11) |
| (since C++20) |
If a template argument can be interpreted as both atype-id and an expression, it is always interpreted as a type-id, even if the corresponding template parameter is constant:
template<class T>void f();// #1 template<int I>void f();// #2 void g(){ f<int()>();// “int()” is both a type and an expression,// calls #1 because it is interpreted as a type}
Before C++26, constant template argument were called non-type template argument in the standard wording. The terminology was changed byP2841R6 /PR #7587.
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_template_template_args | 201611L | (C++17) (DR) | Matching oftemplate template arguments |
__cpp_nontype_template_args | 201411L | (C++17) | Allow constant evaluation for allconstant template arguments |
201911L | (C++20) | Class types and floating-point types inconstant template parameters |
This section is incomplete Reason: no example |
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 150 (P0522R0) | C++98 | template-template arguments had to match parameter lists of template-template parameters exactly | more specialized also allowed |
CWG 354 | C++98 | null pointer values could not be constant template arguments | allowed |
CWG 1398 | C++11 | constant template arguments could not have typestd::nullptr_t | allowed |
CWG 1570 | C++98 | constant template arguments could designate addresses of subobjects | not allowed |
P2308R1 | C++11 C++20 | 1. list-initialization was not allowed for constant template arguments (C++11) 2. it was unclear how constant template parameters of class types are initialized (C++20) | 1. allowed 2. made clear |