Template Member Specialization

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
13
14
15
16
17
18
template<>
template<>
    void foo<X>::bar<Y>()
    {
        std::cout << "World";
    }


Is any reason for that?
Is it possible to specialize only one of those templates? ( specializing the other way round gives similar errors )
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
You could do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;

template <class B>
void bar()
{
    std::cout << "Hello ";
}

template <>
void bar<char>()
{
    std::cout << "World!" << endl;
}

template <class A>
class Foo
{
public:

    template<class B>
    void bar_mem()
    {
        bar<B>();
    }
};

int main()
{
    Foo<int> foo;

    foo.bar_mem<double>();
    foo.bar_mem<char>();

    return 0;
}

But I haven't found a way to pass a Foo instance to global bar... :/
Last edited on
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
using namespace std;

template <class A>
class Foo;

template <class B>
class Bar
{
    template <class A> friend class Foo;

    template <class A>
    void operator()(Foo<A> * foo)
    {
        std::cout << "(" << foo->val << ") ";
        std::cout << "Hello, ";
    }
};

template <>
class Bar<char>
{
    template <class A> friend class Foo;

    template <class A>
    void operator()(Foo<A> * foo)
    {
        std::cout << "(" << foo->val << ") ";
        std::cout << "World!" << endl;
    }
};

template <class A>
class Foo
{
    template<class B> friend class 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()
Last edited on
Look at the remarks for "Template 7"
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> friend class Bar; inside class Foo.
But again, class Bar can't be a member of class Foo and this is not really nice
Bazzy wrote:
I understand that the compiler is not allowing it, but I don't quite understand why.

Neither do I :D

Bazzy wrote:
To be fully functional, your code will need template<class B> friend class Bar; inside class Foo.
Or I could just make it a struct, since the only reason I need it is to serve as a workaround for this problem.
True.

Bazzy wrote:
But again, class Bar can't be a member of class Foo and this is not really nice

Well, I guess if Bar could be a member of Foo then we wouldn't even have the original problem.
Last edited on
Nope, I tried. I get the same error messages as in the first post
Maybe that would need to have another workaround to be done :^P

BTW I don't really need a solution, I found this by playing around with templates. I'm interested in finding out the reason of this restriction
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 
—end example]

Topic archived. No new replies allowed.