JTC1/SC22/WG21
N0743
Document Number: WG21/N0743
X3J16/95-0143
Date: 8 July 1995
Project: Programming Language C++
Reply to: Sean A. Corfield
sean@corf.demon.co.uk
Declaring specialisations - template issue 4.10
Abstract
N0701 = 95-0101 Template Issues and Proposed Resolutions, revision 12, item
4.10 proposes a resolution to how to declare and define specialisations.
Although this resolution had the support of the WG, an alternative was
discussed that also had the support of the WG and was felt by some to be
more consistent with other aspects of templates. The basic idea is that a
specialisation and a primary template are opposite ends of a scale which
has partial specialisations in between. It would therefore be more consistent
if specialisations were syntactic more like both primary templates and
partial specialisations.
This paper proposes that the syntactic notation
template<>
be used to introduce the declaration or definition of a specialisation.
Discussion
Consider the following template declaration:
template<class T, class U, class V> void f(T*, U&, V);
The following are successively more constrained partial specialisations:
template<class U, class V> void f(int*, U&, V);
template<class V> void f(int*, double&, V);
What is the next logical 'partial' specialisation? At present, the next
step is a (full) specialisation whose syntax looks like:
void f<>(int*, double&, char);
This does not have much similarity to the above three declarations. On the
other hand, consider:
template<> void f(int*, double&, char);
This 'looks like' a partial specialisation with an empty list of parameters
yet to be specialised - a full specialisation, in other words.
When member templates are considered, this extra syntactic sugar can be more
helpful:
template<class X> struct A {
template<class Y> struct B;
};
template<class X> template<class Y> struct A<X>::B { };
Here, the two uses of 'template<...>' clearly indicate that a member
template is present, but consider:
template<class Z> struct A<int>::B { };
Is it immediately obvious what this is? A template? A (partial)
specialisation? Now consider this form:
template<> template<class Z> struct A<int>::B { };
Again, the two uses of 'template<...>' indicate a member template is
being declared. The first 'template<>' indicates that the enclosing
template is being specialised; the second, inner, 'template<...>' indicates
that the member template is still not fully specialised.
In my opinion, the primary benefit of the proposed notation is that it is
similar to partial specialisation and, indeed, the original template
declaration, showing more clearly that the specialisation does indeed relate
to a template. Furthermore, the <> that was previously embedded in some
specialisation declarations would no longer be necessary -- it was hard to
spot before anyway.
I also believe that given this change, most of the text of [temp.spec]
could actually be folded into either the foregoing description of template
declarations or the ensuing description of partial specialisations although
I have not attempted to do this in the proposed WP changes.
Proposal
Require specialisations to be declared with the 'template<>' syntax.
WP changes
[Most of the changes in the following are simply the insertion of
'template<>' in the appropriate places -- I have not yet checked the
WP for other places where specialisations appear that would also need to
be changed to use the new notation]
Replace 14.5 [temp.spec] with:
14.5 Template specialization [temp.spec]
1 Except for a type member or template class member of a non-specialized
template class, the following can be declared by a declaration where
the declared name is a template-id: a specialized template function, a
template class, or a static member of a template; that is:
specialization:
template<> declaration
[Note: a static member of a template can only be specialized in a defP
inition due to syntactic restrictions. ] [Example:
template<class T> class stream;
template<> class stream<char> { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
template<> void sort<char*>(Array<char*>&) ;
Given these declarations, stream<char> will be used as the definition
of streams of chars; other streams will be handled by template classes
generated from the class template. Similarly, sort<char*> will be
used as the sort function for arguments of type Array<char*>; other
Array types will be sorted by functions generated from the template.
]
2 A declaration of the template being specialized shall be in scope at
the point of declaration of a specialization. [Example:
template<> class X<int> { /* ... */ }; // error: X not a template
template<class T> class X { /* ... */ };
template<> class X<char*> { /* ... */ }; // fine: X is a template
--end example]
3 If a template is explicitly specialized then that specialization shall
be declared before the first use of that specialization in every
translation unit in which it is used. [Example:
template<class T> void sort(Array<T>& v) { /* ... */ }
void f(Array<String>& v)
{
sort(v); // use general template
// sort(Array<T>&), T is String
}
template<> void sort<String>(Array<String>& v); // error: specialize
// after use
template<> void sort<>(Array<char*>& v); // fine sort<char*> not yet
// used
--end example] If a function or class template has been explicitly
specialized for a template-argument list no specialization will be
implicitly generated for that template-argument list.
4 It is possible for a specialization with a given function signature to
be generated by more than one function template. In such cases,
explicit specification of the template arguments must be used to
uniquely identify the template function instance that is being speP
cialized. [Example:
template <class T> void f(T);
template <class T> void f(T*);
template<> void f(int*); // Ambiguous
template<> void f<int>(int*); // OK
template<> void f(int); // OK
--end example]
5 Note that a function with the same name as a template and a type that
exactly matches that of a template is not a specialization
(_temp.over.spec_).