How is this specialization?
I watched this lecture where the following example is presented as a specialization (@ 29.43):
template<class T>
struct rank
{
static const size_t value = 0u;
}
// partial specialization
template<class U, size_t N>
struct rank<U[N]>
{
static const size_t value = 1 + rank<U>::value;
}
I would expect a compile error, complaining about incompatible struct declarations, and in the second, there are too many template parameters. How is this not a mistake above?
Specializations can have template parameters. Specializations with template parameters are called partial specializations.
template<class T>
struct rank { ...1 };
means rank<T>
- this is a class, and unless otherwise noted ...1
- this is a class definition.
template<class U, size_t N>
struct rank<U[N]> { ...2 };
- this is "otherwise specified": it means that if T
in rank<T>
can be written as U[N]
for some type U
and some constant N
, then ...2
- this is a class definition.
You would use it like rank<int[2]>
, which would use the second class definition with U = int
and N = 2
.
This is not a mistake, because it is valid.
[C++11: 14.5.5/1]:
A main class template declaration is a name where the class template name is an identifier. A template declaration where the class template name is simple-template-id is a partial specialization of the class template named in simple-template-id. A partial specialization of a class template provides an alternative template definition that is used in place of the main definition when the arguments in the specialization match those specified in the partial specialization (14.5.5.1). [..]
There is no simple rule against it, and in fact the standard contains an example of exactly this scenario:
[C++11: 14.5.5/3]:
[Example:
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
The first declaration declares a primary (non-specialized) class. The second and subsequent declarations declare a partial specialization of the primary template. -end example]
The only limitation, which is even slightly related, is ironically closer (though not exactly) to the opposite of what you are claiming:
[C++11: 14.5.5/8]:
The following restrictions apply to the argument list of a template template partial specialization:
- [..]
- The specialization argument list does not have to be identical to the primary template's implicit argument list.
- [..]
You would use primary and templated and partial specializations, for example:
int main()
{
rank<char> a; // uses the primary
rank<int[5]> b; // uses the partial spec.
}