[temp.class.spec] (original) (raw)

13 Templates [temp]

13.7 Template declarations [temp.decls]

13.7.6 Class template partial specializations [temp.class.spec]

13.7.6.1 General [temp.class.spec.general]

Aprimary class templatedeclaration is one in which the class template name is an identifier.

A partial specialization of a class 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.class.spec.match]).

The primary template shall be declared before any specializations of that template.

A partial specialization shall be declared before the first use of a class template specialization that would make use of the partial specialization as the result of an implicit or explicit instantiation in every translation unit in which such a use occurs; no diagnostic is required.

Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization ([temp.class.spec.mfunc]).

[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 class template partial specialization may be constrained ([temp.pre]).

[Example 2: template<typename T> concept C = true;template<typename T> struct X { };template<typename T> struct X<T*> { }; template<C T> struct X<T> { };

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 parameters are specified in the angle bracket enclosed list that immediately follows the keywordtemplate.

For partial specializations, the template argument list is explicitly written immediately following the class template name.

For primary templates, this list is implicitly described by the template parameter list.

Specifically, the order of the template arguments is the sequence in which they appear in the template parameter list.

[Example 3:

The template argument list for the primary template in the example above is<T1, T2, I>.

— _end example_]

[Note 1:

The template argument list cannot be specified in the primary template declaration.

For example,

template<class T1, class T2, int I> class A<T1, T2, I> { }; — _end note_]

A class template partial specialization may be declared in any scope in which the corresponding primary template may be defined ([namespace.memdef], [class.mem], [temp.mem]).

[Example 4: template<class T> struct A { struct C { template<class T2> struct B { };template<class T2> struct B<T2**> { }; };};template<class T> template<class T2> struct A<T>::C::B<T2*> { }; A<short>::C::B<int*> absip; — _end example_]

Partial specialization declarations themselves are not found by name lookup.

Rather, when the primary template name is used, any previously-declared partial specializations of the primary template are also considered.

One consequence is that ausing-declarationwhich refers to a class template does not restrict the set of partial specializations which may be found through theusing-declaration.

[Example 5: namespace N { template<class T1, class T2> class A { }; } using N::A; namespace N { template<class T> class A<T, T*> { }; }A<int,int*> a; — _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 class template partial specialization, the following restrictions apply:

The usual access checking rules do not apply to non-dependent names used to specify template arguments of the simple-template-idof 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_]

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

When a class template is used in a context that requires an instantiation of the class, 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 class template specialization with the template argument lists of the partial specializations.

A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can bededuced from the actual template argument list, and the deduced template arguments satisfy the associated constraintsof the partial specialization, if any.

[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> { }; A<int, int, 1> a1; A<int, int*, 1> a2; A<int, char*, 5> a3; A<int, char*, 1> a4; A<int*, int*, 2> a5; — _end example_]

[Example 2: template<typename T> concept C = requires (T t) { t.f(); };template<typename T> struct S { }; template<C T> struct S<T> { }; struct Arg { void f(); }; S<int> s1; S<Arg> s2; — _end example_]

If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-listand 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> {}; template <int I> struct A<I, I> {}; template <int I, int J, int K> struct B {};template <int I> struct B<I, I*2, 2> {}; — _end example_]

In a type name that refers to a class template specialization, (e.g.,A<int, int, 1>) the argument list shall match the template parameter list of the primary template.

The template arguments of a specialization are deduced from the arguments of the primary template.

13.7.6.3 Partial ordering of class template specializations [temp.class.order]

For two class template 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:

[Example 1: template<int I, int J, class T> class X { };template<int I, int J> class X<I, J, int> { }; template<int I> class X<I, I, int> { }; template<int I0, int J0> void f(X<I0, J0, int>); template<int I0> void f(X<I0, I0, int>); template <auto v> class Y { };template <auto* p> class Y<p> { }; template <auto** pp> class Y<pp> { }; template <auto* p0> void g(Y<p0>); template <auto** pp0> void g(Y<pp0>);

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> { }; template<D T> class S<T> { }; template<C T> void f(S<T>); template<D T> void f(S<T>);

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 specializations [temp.class.spec.mfunc]

The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.

The template argument list of a member of a class template partial specialization shall match the template argument list of the class template partial specialization.

A class template partial specialization is a distinct template.

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 the primary template.

[Example 1: template<class T, int I> struct A { void f();};template<class T, int I> void A<T,I>::f() { } template<class T> struct A<T,2> { void f();void g();void h();};template<class T> void A<T,2>::g() { } template<> void A<char,2>::h() { } int main() { A<char,0> a0; A<char,2> a2; a0.f(); a2.g(); a2.h(); a2.f(); } — _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 {}; template<class T2> struct B<T2*> {}; };template<> template<class T2> struct A<short>::B {}; A<char>::B<int*> abcip; A<short>::B<int*> absip; A<char>::B<int> abci; — _end example_]