5
votes

I can use partial template specialization inside class declaration

template<class T1, class T2>
struct A
{
    void foo() { cout << "general"; }
};

template<class T1>
struct A<T1, int>
{
    void foo() { cout << "partial specialization"; }
};

But when I'm trying to do it outside class declaration

template<class T1, class T2>
struct A
{
    void foo();
};


template<class T1, class T2>
void A<T1, T2>::foo() { cout << "general"; }

template<class T1>
void A<T1, int>::foo() { cout << "partial specialization"; }

I get the following error:

invalid use of incomplete type «struct A < T1, int >»

It's not a problem to use the first approach when you want to redefine all members, but what if you want redefine only one method without code duplication for all others?

So, is it possible to use partial template specialization outside class definition?

4

4 Answers

3
votes

It's not a problem to use the first approach when you want to redefine all members, but what if you want redefine only one method without code duplication for all others?

This is where traits technique can be used. See http://www.boost.org/community/generic_programming.html#traits

Some usage:

template <class T1, class T2>
struct ATraits {
   static void foo() {}
};

template <class T1>
struct ATraits<T1,int> {
   static void foo() {}
};

template <class T1, class T2>
struct A {
   void foo() { ATraits<T1,T2>::foo(); }
};
3
votes

In your failing example:

template<class T1>
void A<T1, int>::foo() { cout << "partial specialization"; }

You are referring to a specialization of A which you haven't defined yet (you have only defined the full template in the second example).

If you add the specialization before you refer to it, it should indeed work:

template <class T1>
struct A<T1, int>
{
  void foo ();
};

template <class T1>
void A<T1, int>::foo ()
{
  /* something */
};
2
votes

Specializing a method without fully specializing the outer template is forbidden by the c++ standard. So yeah it is not possible. I am not sure if it is valid for c++11 but I suspect it is.

One way to work around this is to specialize the outer template as you have done in the first example.

Btw this might be another workaround:

template<class T1, class T2>
struct A
{
    template<unsigned int I>
    void foo() { cout << "general"; }

    template<>
    void foo<2> () { cout << "specialization"; }

};

This works because this is not a specialization but different template for the method.

0
votes

The same topic is discussed here: "invalid use of incomplete type" error with partial template specialization

+1 for tozka's solution, if A does not need to know I except for foo(), this is a nice workaround. Otherwise have a look at the answers to the atop mentioned question.