C++ syntax for explicit specialization of a template function in a template class?
I have code which works in VC9 (Microsoft Visual C++ 2008 SP1) but not in GCC 4.2 (on Mac):
struct tag {};
template< typename T >
struct C
{
template< typename Tag >
void f( T ); // declaration only
template<>
inline void f< tag >( T ) {} // ERROR: explicit specialization in
}; // non-namespace scope 'structC<T>'
I understand that GCC would like me to move my explicit specialization outside the class but I can't figure out the syntax. Any ideas?
// the following is not correct syntax, what is?
template< typename T >
template<>
inline void C< T >::f< tag >( T ) {}
Solution 1:
You can't specialize a member function without explicitly specializing the containing class.
What you can do however is forward calls to a member function of a partially specialized type:
template<class T, class Tag>
struct helper {
static void f(T);
};
template<class T>
struct helper<T, tag1> {
static void f(T) {}
};
template<class T>
struct C {
// ...
template<class Tag>
void foo(T t) {
helper<T, Tag>::f(t);
}
};
Solution 2:
GCC is in the clear, here. MSVC has a non-standard extension that allows in-class specialization. The standard, however, says:
14.7.3.2:
2. An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member. An explicit specialization of a member function, member class or static data member of a class template shall be declared in the namespace of which the class template is a member.
Additionally, you can't partially specialize a function. (Though I'm unsure about the details in your case, that would be the final blow.)
You could do this:
#include <iostream>
struct true_type {};
struct false_type {};
template <typename T, typename U>
struct is_same : false_type
{
static const bool value = false;
};
template <typename T>
struct is_same<T, T> : true_type
{
static const bool value = true;
};
struct tag1 {};
struct tag2 {};
template< typename T >
struct C
{
typedef T t_type;
template< typename Tag >
void foo( t_type pX)
{
foo_detail( pX, is_same<Tag, tag1>() );
}
private:
void foo_detail( t_type, const true_type& )
{
std::cout << "In tag1 version." << std::endl;
}
void foo_detail( t_type, const false_type& )
{
std::cout << "In not tag1 version." << std::endl;
}
};
int main(void)
{
C<int> c;
c.foo<tag1>(int());
c.foo<tag2>(int());
c.foo<double>(int());
}
Though this is somewhat ugly.
Solution 3:
Came across this question. This should work:
struct tag {};
template< typename T >
struct C {
template< typename Tag, typename std::enable_if<std::is_same<Tag, tag>::value, int>::type = 0>
void f( T ){
std::cout<<"tag type" <<std::endl;
}
template< typename Tag, typename std::enable_if<!std::is_same<Tag, tag>::value, int>::type = 0>
void f( T ){
std::cout<<"non tag type" <<std::endl;
}
};
Solution 4:
I know this may not satisfy you, but I do not believe you may not have a specialization enclosed within a non-explicitly-specialized structure.
template<>
template<>
inline void C< tag1 >::foo< tag2 >( t_type ) {}