I'm trying to specialize a template member function of a non-template class using a templatized parameter:
#include <array>
class C
{
public:
template<class Container>
void Foo( Container& )
{
// ...
}
};
template<class T, std::size_t N>
template<>
void C::Foo< std::tr1::array<T,N> >( std::tr1::array<T,N>& )
{
// special
}
I get an error "illegal use of explicit template arguments" with this. What's the right syntax to make this valid?
Update:
Perhaps I've muddled the issue by over-simplifying. What I really want to do is specially handle this one case where there is a dependent name involved, which I think may be what is throwing a monkey wrench into the works here. My original thought was to overload the function as suc开发者_开发百科h:
class C
{
public:
template<class Iter>
void Foo( Iter )
{
std::cout << "Normal\n";
}
template<class T, std::size_t N>
void Foo( typename std::tr1::array<T,N>::iterator )
{
std::cout << "Special\n";
}
};
int main()
{
C c;
std::tr1::array<int,10> a1;
c.Foo( a1.begin() ); // Doesn't print "Special"!
}
But the special Foo doesn't get called. How can I do that?
Only the member function is templated, which means that you should only use one template<...>
in there. But that will not solve it either, as you cannot partially specialize a function.
The usual way of handling the problem is through overloads, rather than specialization (specialization of template functions is not that useful).
struct test {
template <typename Container>
void f( Container& ) { ... }
template <typename T, int N>
void f( std::array<T,N>& ) { ... }
};
Note that the difference is that they are two separate template functions (rather than an specialization).
EDIT: After the update
The update to the question changes the problem completely. The problem that you are seeing is that the argument of the second version is a dependent name, and as such it is non deducible. Given the function call the compiler is not able to determine what type T, and integral constant N are to match that particular instantiation. Consider a different example:
template <typename T>
struct inner_int {
typedef int type;
};
template <typename T>
void foo( typename inner_int<T>::type ) {
}
int main() {
foo( inner_int<double>::type() );
}
When the compiler processes the call in main
, it instantiates the template and extracts the type, from that it creates a temporary, and then it tries to decide what to do with foo
but at that time it only knows that it is being called with an int
rvalue... the original inner<double>::type
is gone, now it is just foo( int() )
and the compiler would have to try and instantiate inner_int
with all possible types to determine whether any of them fits, and in the worse case, as above, many would match.
Partial function template specialization is illegal. From the C++03 standard, §14/2:
A template-declaration can appear only as a namespace scope or class scope declaration. In a function template declaration, the declarator-id shall be a template-name (i.e., not a template-id). [Note: in a class template declaration, if the class name is a template-id, the declaration declares a class template partial specialization.]
You'll want to simply overload your function instead:
class C
{
public:
template<typename Container>
void Foo(Container&)
{
// ...
}
template<typename T, std::size_t N>
void Foo(std::tr1::array<T, N>&)
{
// special
}
};
EDIT (in response to the OP's edit):
If you're only looking for a workaround for this specific scenario, since std(::tr1)::array<T,N>::iterator
is simply T*
, your 'special' overload can be:
template<typename T>
void Foo(T*&)
{
// special
}
精彩评论