Why template parameter lists need not match in partial specialization?
Hello everybody!
I have just been playing around a little with partial specialization and
noticed that there is a potential danger of making mistakes that maybe could
have been avoided. Please take a look at the following code:
#include <vector>
#include <iostream>
// Regular template for any type.
template <typename T>
struct is_vector
{
static const bool result = false;
};
// Partial specialization for std::vector.
template <typename T>
struct is_vector<std::vector<T>>
{
static const bool result = true;
};
/*
// Partial specialization for std::vector
// with a divergent allocator type.
template <typename T, typename U>
struct is_vector<std::vector<T, std::allocator<U>>>
{
static const bool result = true;
};
*/
int main()
{
using std::cout;
using std::endl;
// Output: 0
cout << is_vector<int>::result << endl;
// Output: 1
cout << is_vector<std::vector<int>>::result << endl;
// Output: 1
cout << is_vector<std::vector<int, std::allocator<int>>>::result <<
endl;
// Output: 0, unless the second partial specialization is not commented
out
cout << is_vector<std::vector<int, std::allocator<double>>>::result <<
endl;
return 0;
}
The output of the first three tests are not surprising, but that of the last
is unexpected. If the code for the partial specialization for std::vector
with a divergent allocator type is commented out, the regular template gets
instantiated for std::vector<int, std::allocator<double>>, although the
template argument is a std::vector.
You have to provide the second partial specialization in order to get the
expected result. On my compiler, the second and third test for
std::vector<int> and std::vector<int, std::allocator<int>>, respectively,
instantiate the "simple" partial specialization even if the one for
divergent allocator types is available. I assume that this is what the
standard requires.
I also found out that the "simple" partial specialization is unnecessary if
the other one is provided, which is not surprising. What surprises me,
however, is that it is possible to provide a partial specialization using
"std::vector<T>" as a parameter and later provide a "std::vector<int,
std::allocator<int>>" as an argument. The reason why this surprises me is
that the number of template parameters does not match. The partial
specialization
template <typename T>
struct is_vector<std::vector<T>> { ... }
should apply to a type that has a single template parameter, but std::vector
actually has two of them, one has a default argument of "std::allocator<T>".
And as I stated at the beginning of this post, I consider this potentially
dangerous because it is easy to forget about the default argument and write
a partial specialization like
template <typename T>
struct is_vector<std::vector<T>> { ... }
while you would actually have to write something like
template <typename T, typename U>
struct is_vector<std::vector<T, std::allocator<U>>> { ... }
Is there any reason why the standard permits this? I recently found out that
when using template template arguments, the number of parameters must match,
i.e. the following template class can not be used for a std::vector:
template<template <typename> class Cont>
class MyClass
{
Cont<int> m_cont;
};
int main()
{
// Error: The template parameter list
// for class template 'std::vector' does
// not match the template parameter list
// for template parameter 'Cont'.
MyClass<std::vector> obj;
return 0;
}
In order for this code to compile, 'MyClass' must be redefined as follows:
template<template <typename, typename> class Cont>
class MyClass
{
Cont<int, std::allocator<int>> m_cont;
};
To summarize things, the template parameter lists must match in the case of
a template template parameter, but they need not match in the case of a
partial specialization, which makes the latter somewhat error prone. Is
there any reason for this?
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]