13 Templates [temp]

13.7 Template declarations [temp.decls]

13.7.6 Partial specialization [temp.spec.partial]

13.7.6.1 General [temp.spec.partial.general]

A partial specialization of a template provides an alternative definition of the template that is used instead of the primary definition when the arguments in a specialization match those given in the partial specialization ([temp.spec.partial.match]).
A declaration of the primary template shall precede any partial specialization of that template.
A partial specialization shall be reachable from any use of a template specialization that would make use of the partial specialization as the result of an implicit or explicit instantiation; no diagnostic is required.
Two partial specialization declarations declare the same entity if they are partial specializations of the same template and have equivalent template-heads and template argument lists ([temp.over.link]).
Each partial specialization is a distinct template.
[Example 1: template<class T1, class T2, int I> class A { }; template<class T, int I> class A<T, T*, I> { }; template<class T1, class T2, int I> class A<T1*, T2, I> { }; template<class T> class A<int, T*, 5> { }; template<class T1, class T2, int I> class A<T1, T2*, I> { };
The first declaration declares the primary (unspecialized) class template.
The second and subsequent declarations declare partial specializations of the primary template.
— end example]
A partial specialization may be constrained ([temp.constr]).
[Example 2: template<typename T> concept C = true; template<typename T> struct X { }; template<typename T> struct X<T*> { }; // #1 template<C T> struct X<T> { }; // #2
Both partial specializations are more specialized than the primary template.
#1 is more specialized because the deduction of its template arguments from the template argument list of the class template specialization succeeds, while the reverse does not.
#2 is more specialized because the template arguments are equivalent, but the partial specialization is more constrained ([temp.constr.order]).
— end example]
The template argument list of a partial specialization is the template-argument-list following the name of the template.
A partial specialization may be declared in any scope in which the corresponding primary template may be defined ([dcl.meaning], [class.mem], [temp.mem]).
[Example 3: template<class T> struct A { struct C { template<class T2> struct B { }; template<class T2> struct B<T2**> { }; // partial specialization #1 }; }; // partial specialization of A<T>​::​C​::​B<T2> template<class T> template<class T2> struct A<T>::C::B<T2*> { }; // #2 A<short>::C::B<int*> absip; // uses partial specialization #2 — end example]
Partial specialization declarations do not introduce a name.
Instead, when the primary template name is used, any reachable partial specializations of the primary template are also considered.
[Note 1:
One consequence is that a using-declaration which refers to a class template does not restrict the set of partial specializations that are found through the using-declaration.
— end note]
[Example 4: namespace N { template<class T1, class T2> class A { }; // primary template } using N::A; // refers to the primary template namespace N { template<class T> class A<T, T*> { }; // partial specialization } A<int,int*> a; // uses the partial specialization, which is found through the using-declaration // which refers to the primary template — end example]
A non-type argument is non-specialized if it is the name of a non-type parameter.
All other non-type arguments are specialized.
Within the argument list of a partial specialization, the following restrictions apply:
  • The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the partial specialization.
    [Example 5: template <class T, T t> struct C {}; template <class T> struct C<T, 1>; // error template< int X, int (*array_ptr)[X] > class A {}; int array[5]; template< int X > class A<X,&array> { }; // error — end example]
  • The partial specialization shall be more specialized than the primary template ([temp.spec.partial.order]).
  • The template parameter list of a partial specialization shall not contain default template argument values.128
  • An argument shall not contain an unexpanded pack.
    If an argument is a pack expansion ([temp.variadic]), it shall be the last argument in the template argument list.
The usual access checking rules do not apply to non-dependent names used to specify template arguments of the simple-template-id of the partial specialization.
[Note 2:
The template arguments can be private types or objects that would normally not be accessible.
Dependent names cannot be checked when declaring the partial specialization, but will be checked when substituting into the partial specialization.
— end note]
128)128)
There is no context in which they would be used.

13.7.6.2 Matching of partial specializations [temp.spec.partial.match]

When a template is used in a context that requires an instantiation of the template, it is necessary to determine whether the instantiation is to be generated using the primary template or one of the partial specializations.
This is done by matching the template arguments of the template specialization with the template argument lists of the partial specializations.
  • If exactly one matching partial specialization is found, the instantiation is generated from that partial specialization.
  • If more than one matching partial specialization is found, the partial order rules ([temp.spec.partial.order]) are used to determine whether one of the partial specializations is more specialized than the others.
    If such a partial specialization exists, the instantiation is generated from that partial specialization; otherwise, the use of the template is ambiguous and the program is ill-formed.
  • If no matches are found, the instantiation is generated from the primary template.
A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list, and the deduced template arguments satisfy the associated constraints of the partial specialization, if any.
[Example 1: template<class T1, class T2, int I> class A { }; // #1 template<class T, int I> class A<T, T*, I> { }; // #2 template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3 template<class T> class A<int, T*, 5> { }; // #4 template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5 A<int, int, 1> a1; // uses #1 A<int, int*, 1> a2; // uses #2, T is int, I is 1 A<int, char*, 5> a3; // uses #4, T is char A<int, char*, 1> a4; // uses #5, T1 is int, T2 is char, I is 1 A<int*, int*, 2> a5; // ambiguous: matches #3 and #5 — end example]
[Example 2: template<typename T> concept C = requires (T t) { t.f(); }; template<typename T> struct S { }; // #1 template<C T> struct S<T> { }; // #2 struct Arg { void f(); }; S<int> s1; // uses #1; the constraints of #2 are not satisfied S<Arg> s2; // uses #2; both constraints are satisfied but #2 is more specialized — end example]
If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-list and the template-id, the program is ill-formed.
[Example 3: template <int I, int J> struct A {}; template <int I> struct A<I+5, I*2> {}; // error template <int I> struct A<I, I> {}; // OK template <int I, int J, int K> struct B {}; template <int I> struct B<I, I*2, 2> {}; // OK — end example]
In a name that refers to a specialization of a class or variable template (e.g., A<int, int, 1>), the argument list shall match the template parameter list of the primary template.
The template arguments of a partial specialization are deduced from the arguments of the primary template.

13.7.6.3 Partial ordering of partial specializations [temp.spec.partial.order]

For two partial specializations, the first is more specialized than the second if, given the following rewrite to two function templates, the first function template is more specialized than the second according to the ordering rules for function templates:
  • Each of the two function templates has the same template parameters and associated constraints as the corresponding partial specialization.
  • Each function template has a single function parameter whose type is a class template specialization where the template arguments are the corresponding template parameters from the function template for each template argument in the template-argument-list of the simple-template-id of the partial specialization.
[Example 1: template<int I, int J, class T> class X { }; template<int I, int J> class X<I, J, int> { }; // #1 template<int I> class X<I, I, int> { }; // #2 template<int I0, int J0> void f(X<I0, J0, int>); // A template<int I0> void f(X<I0, I0, int>); // B template <auto v> class Y { }; template <auto* p> class Y<p> { }; // #3 template <auto** pp> class Y<pp> { }; // #4 template <auto* p0> void g(Y<p0>); // C template <auto** pp0> void g(Y<pp0>); // D
According to the ordering rules for function templates, the function template B is more specialized than the function template A and the function template D is more specialized than the function template C.
Therefore, the partial specialization #2 is more specialized than the partial specialization #1 and the partial specialization #4 is more specialized than the partial specialization #3.
— end example]
[Example 2: template<typename T> concept C = requires (T t) { t.f(); }; template<typename T> concept D = C<T> && requires (T t) { t.f(); }; template<typename T> class S { }; template<C T> class S<T> { }; // #1 template<D T> class S<T> { }; // #2 template<C T> void f(S<T>); // A template<D T> void f(S<T>); // B
The partial specialization #2 is more specialized than #1 because B is more specialized than A.
— end example]

13.7.6.4 Members of class template partial specializations [temp.spec.partial.member]

The members of the class template partial specialization are unrelated to the members of the primary template.
Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization.
An explicit specialization of a member of a class template partial specialization is declared in the same way as an explicit specialization of a member of the primary template.
[Example 1: // primary class template template<class T, int I> struct A { void f(); }; // member of primary class template template<class T, int I> void A<T,I>::f() { } // class template partial specialization template<class T> struct A<T,2> { void f(); void g(); void h(); }; // member of class template partial specialization template<class T> void A<T,2>::g() { } // explicit specialization template<> void A<char,2>::h() { } int main() { A<char,0> a0; A<char,2> a2; a0.f(); // OK, uses definition of primary template's member a2.g(); // OK, uses definition of partial specialization's member a2.h(); // OK, uses definition of explicit specialization's member a2.f(); // error: no definition of f for A<T,2>; the primary template is not used here } — end example]
If a member template of a class template is partially specialized, the member template partial specializations are member templates of the enclosing class template; if the enclosing class template is instantiated ([temp.inst], [temp.explicit]), a declaration for every member template partial specialization is also instantiated as part of creating the members of the class template specialization.
If the primary member template is explicitly specialized for a given (implicit) specialization of the enclosing class template, the partial specializations of the member template 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 specialization of the enclosing class template.
[Example 2: template<class T> struct A { template<class T2> struct B {}; // #1 template<class T2> struct B<T2*> {}; // #2 }; template<> template<class T2> struct A<short>::B {}; // #3 A<char>::B<int*> abcip; // uses #2 A<short>::B<int*> absip; // uses #3 A<char>::B<int> abci; // uses #1 — end example]