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 | ||||||||||||||||
|
General | ||||
Literals | ||||
Operators | ||||
Conversions | ||||
Template parameters | ||||
Template arguments | ||||
Class templates | ||||
Function templates | ||||
Class member templates | ||||
Variable templates(C++14) | ||||
Template argument deduction | ||||
Class template argument deduction(C++17) | ||||
Explicit (full) specialization | ||||
Partial specialization | ||||
Dependent names | ||||
Packs(C++11) | ||||
sizeof...(C++11) | ||||
Fold expressions(C++17) | ||||
Pack indexing(C++26) | ||||
SFINAE | ||||
Constraints and concepts(C++20) | ||||
requires expression(C++20) |
Allows customizing classand variable(since C++14) templates for a given category of template arguments.
Contents |
template < parameter-list> class-keyclass-head-name< argument-list> declaration | (1) | ||||||||
template < parameter-list> decl-specifier-seqdeclarator< argument-list> initializer (optional) | (2) | (since C++14) | |||||||
whereclass-head-name identifies the name of a previously declaredclass template anddeclarator identifies the name of a previously declaredvariable template(since C++14).
Partial specialization may be declared in any scope where its primary template may be defined (which may be different from the scope where the primary template is defined; such as with out-of-class specialization of amember template). Partial specialization has to appear after the non-specialized template declaration.
For example,
template<class T1,class T2,int I>class A{};// primary template template<class T,int I>class A<T, T*, I>{};// #1: partial specialization where T2 is a pointer to T1 template<class T,class T2,int I>class A<T*, T2, I>{};// #2: partial specialization where T1 is a pointer template<class T>class A<int, T*,5>{};// #3: partial specialization where// T1 is int, I is 5, and T2 is a pointer template<class X,class T,int I>class A<X, T*, I>{};// #4: partial specialization where T2 is a pointer
Examples of partial specializations in the standard library includestd::unique_ptr, which has a partial specialization for array types.
The following restrictions apply to theargument-list of a partial template specialization:
template<class T1,class T2,int I>class B{};// primary templatetemplate<class X,class Y,int N>class B<X, Y, N>{};// error
Moreover, the specialization has to be more specialized than the primary template template<int N,typename T1,typename...Ts>struct B;template<typename...Ts>struct B<0, Ts...>{};// Error: not more specialized | (since C++11) |
template<int I,int J>struct A{};template<int I>struct A<I+5, I*2>{};// error, I is not deducible template<int I,int J,int K>struct B{};template<int I>struct B<I, I*2,2>{};// OK: first parameter is deducible
template<class T, T t>struct C{};// primary templatetemplate<class T>struct C<T,1>;// error: type of the argument 1 is T,// which depends on the parameter T template<int X,int(*array_ptr)[X]>class B{};// primary templateint array[5];template<int X>class B<X,&array>{};// error: type of the argument &array is// int(*)[X], which depends on the parameter X
Partial template specializations are not found by name lookup. Only if the primary template is found by name lookup, its partial specializations are considered. In particular, a using declaration that makes a primary template visible, makes partial specializations visible as well:
namespace N{template<class T1,class T2>class Z{};// primary template}using N::Z;// refers to the primary template namespace N{template<class T>class Z<T, T*>{};// partial specialization}Z<int,int*> z;// name lookup finds N::Z (the primary template), the// partial specialization with T = int is then used
When a classor variable(since C++14) template is instantiated, and there are partial specializations available, the compiler has to decide if the primary template is going to be used or one of its partial specializations.
// given the template A as defined aboveA<int,int,1> a1;// no specializations match, uses primary templateA<int,int*,1> a2;// uses partial specialization #1 (T = int, I = 1)A<int,char*,5> a3;// uses partial specialization #3, (T = char)A<int,char*,1> a4;// uses partial specialization #4, (X = int, T = char, I = 1)A<int*,int*,2> a5;// error: matches #2 (T = int, T2 = int*, I= 2)// matches #4 (X = int*, T = int, I = 2)// neither one is more specialized than the other
Informally "A is more specialized than B" means "A accepts a subset of the types that B accepts".
Formally, to establish more-specialized-than relationship between partial specializations, each is first converted to a fictitious function template as follows:
The function templates are then ranked as if forfunction template overloading.
template<int I,int J,class T>struct X{};// primary templatetemplate<int I,int J>struct X<I, J,int>{staticconstint s=1;};// partial specialization #1// fictitious function template for #1 is// template<int I, int J> void f(X<I, J, int>); #A template<int I>struct X<I, I,int>{staticconstint s=2;};// partial specialization #2// fictitious function template for #2 is// template<int I> void f(X<I, I, int>); #B int main(){ X<2,2,int> x;// both #1 and #2 match// partial ordering for function templates:// #A from #B: void(X<I, J, int>) from void(X<U1, U1, int>): deduction OK// #B from #A: void(X<I, I, int>) from void(X<U1, U2, int>): deduction fails// #B is more specialized// #2 is the specialization that is instantiatedstd::cout<< x.s<<'\n';// prints 2}
The template parameter list and the template argument list of a member of a partial specialization must match the parameter list and the argument list of the partial specialization.
Just like with members of primary templates, they only need to be defined if used in the program.
Members of partial specializations are not related to the members of the primary template.
Explicit (full) specialization of a member of a partial specialization is declared the same way as an explicit specialization of the primary template.
template<class T,int I>// primary templatestruct A{void f();// member declaration}; template<class T,int I>void A<T, I>::f(){}// primary template member definition // partial specializationtemplate<class T>struct A<T,2>{void f();void g();void h();}; // member of partial specializationtemplate<class T>void A<T,2>::g(){} // explicit (full) specialization// of a member of partial specializationtemplate<>void A<char,2>::h(){} int main(){ A<char,0> a0; A<char,2> a2; a0.f();// OK, uses primary template’s member definition a2.g();// OK, uses partial specialization's member definition a2.h();// OK, uses fully-specialized definition of// the member of a partial specialization a2.f();// error: no definition of f() in the partial// specialization A<T,2> (the primary template is not used)}
If a primary template is a member of another class template, its partial specializations are members of the enclosing class template. If the enclosing template is instantiated, the declaration of each member partial specialization is instantiated as well (the same way declarations, but not definitions, of all other members of a template are instantiated).
If the primary member template is explicitly (fully) specialized for a given (implicit) specialization of the enclosing class template, the partial specializations of the membertemplate are ignored for this specialization of the enclosing class template.
If a partial specialization of the member template is explicitly specialized for a given (implicit) specialization of the enclosing class template, the primary member template and its other partial specializations are still considered for this specializationof the enclosing class template.
template<class T>struct A// enclosing class template{template<class T2>struct B{};// primary member templatetemplate<class T2>struct B<T2*>{};// partial specialization of member template}; template<>template<class T2>struct A<short>::B{};// full specialization of primary member template// (will ignore the partial) A<char>::B<int*> abcip;// uses partial specialization T2=intA<short>::B<int*> absip;// uses full specialization of the primary (ignores partial)A<char>::B<int> abci;// uses primary
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 727 | C++98 | partial and full specializations not allowed in class scope | allowed in any scope |
CWG 1315 | C++98 | template parameter could not be used in constant template arguments other than id-expressions | expressions ok as long as deducible |
CWG 1495 | C++11 | the specification was unclear when involving parameter pack | the specialization shall be more specialized |
CWG 1711 | C++14 | missing specification of variable template partial specializations | add support for variable templates |
CWG 1819 | C++98 | acceptable scopes for definition of partial specialization | make partial specialization can be declared in the same scope with primary templates |
CWG 2330 | C++14 | missing references to variable templates | add support for variable templates |