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.
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*>{}; // #1template<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]).
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]
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 templatenamespace 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]
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>; // errortemplate<int X, int(*array_ptr)[X]>class A {};
int array[5];
template<int X >class A<X,&array>{}; // error — end example]
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.
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 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.
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 {}; // #1template<class T, int I>class A<T, T*, I>{}; // #2template<class T1, class T2, int I>class A<T1*, T2, I>{}; // #3template<class T>class A<int, T*, 5>{}; // #4template<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 {}; // #1template<C T>struct S<T>{}; // #2struct 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>{}; // errortemplate<int I>struct A<I, I>{}; // OKtemplate<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.
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 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>{}; // #1template<int I>class X<I, I, int>{}; // #2template<int I0, int J0>void f(X<I0, J0, int>); // Atemplate<int I0>void f(X<I0, I0, int>); // Btemplate<auto v>class Y {};
template<auto* p>class Y<p>{}; // #3template<auto** pp>class Y<pp>{}; // #4template<auto* p0>void g(Y<p0>); // Ctemplate<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>{}; // #1template<D T>class S<T>{}; // #2template<C T>void f(S<T>); // Atemplate<D T>void f(S<T>); // B
The partial specialization #2 is more specialized than #1
because B is more specialized than A.
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 templatetemplate<class T, int I>struct A {void f();
};
// member of primary class templatetemplate<class T, int I>void A<T,I>::f(){}// class template partial specializationtemplate<class T>struct A<T,2>{void f();
void g();
void h();
};
// member of class template partial specializationtemplate<class T>void A<T,2>::g(){}// explicit specializationtemplate<>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.