I was trying to specialize a template method of a template class but I can't get it to work properly.
The following code works fine if class foo isn't a template:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
template < class A >
class foo
{
public:
template<class B>
void bar()
{
std::cout << "Hello";
}
};
template < class A >
template<>
void foo<A>::bar<X>()
{
std::cout << "World";
}
But with the template stuff g++ gives these errors:
Line 14: invalid explicit specialization before ‘>’ token
Line 14: enclosing class templates are not explicitly specialized
Line 15: template-id ‘bar<A>’ for ‘void foo<A>::bar()’ does not match any template declaration
( using foo<A>::template bar<X> doesn't make any difference )
It works if I specialize the class at the same time
Actually I didn't find a reasonable explanation to that right away. But, is your bar() function really having no parameters? I mean why make it a template if it doesn't hold any parameters?
That was only an example, I don't understand why that's not possible / which is the correct way to do it.
BTW in a general situation a function may need to be a template but without having parameters depending on the template arguments
Ok, I got it working! Since when you specialize a template chain you must specialize from the left to the right, you just have to somehow reverse the order here. Am I awesome or what?! :D
#include <iostream>
usingnamespace std;
template <class A>
class Foo;
template <class B>
class Bar
{
template <class A> friendclass Foo;
template <class A>
voidoperator()(Foo<A> * foo)
{
std::cout << "(" << foo->val << ") ";
std::cout << "Hello, ";
}
};
template <>
class Bar<char>
{
template <class A> friendclass Foo;
template <class A>
voidoperator()(Foo<A> * foo)
{
std::cout << "(" << foo->val << ") ";
std::cout << "World!" << endl;
}
};
template <class A>
class Foo
{
template<class B> friendclass Bar;
A val;
public:
Foo(A a):val(a){}
template<class B>
void bar()
{
Bar<B>()(this);
}
};
int main()
{
Foo<char> foo1('F');
Foo<int> foo2(-2);
foo1.bar<double>();
foo2.bar<char>();
return 0;
}
EDIT: Reworked the code a bit (made Bar a friend of Foo), according to the suggestion below.
EDIT 2: Reworked the code a bit more (made Bar::operator() private and Foo a friend of Bar), so that nobody else than Foo can directly access Bar::operator()
I understand that the compiler is not allowing it, but I don't quite understand why.
To be fully functional, your code will need template<class B> friendclass Bar; inside class Foo.
But again, class Bar can't be a member of class Foo and this is not really nice
I'm reading the template part of the ISO document, I wonder how a human being can understand some of that. But at least I think I found something:
In an explicit specialization declaration for a member of a class template or a member template that appears
in namespace scope, the member template and some of its enclosing class templates may remain unspecial-
ized, except that the declaration shall not explicitly specialize a class member template if its enclosing class
templates are not explicitly specialized as well. In such explicit specialization declaration, the keyword
template followed by a template-parameter-list shall be provided instead of the template<> preced-
ing the explicit specialization declaration of the member. The types of the template-parameters in the
template-parameter-list shall be the same as those specified in the primary template definition. [Example:
1 2 3 4 5 6 7 8 9 10 11 12
template<class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template<> template<class X>
class A<int>::B { };
template<> template<> template<class T>
void A<int>::B<double>::mf1(T t) { }
template<class Y> template<> // ill-formed; B<double> is specialized but
void A<Y>::B<double>::mf2() { } // its enclosing class template A is not