12

Is there a partial specialization for template class method?

 template <class A, class B>
 class C
 {
  void foo();
 }

it doesn't work to specialize it like this:

template <class A> void C<A, CObject>::foo() {};

Any help?

1

6 Answers 6

12

If you are already have specialized class you could give different implementation of foo in specialized class:

template<typename A, typename B>
class C
{
public:
    void foo() { cout << "default" << endl; };
};

template<typename A>
class C<A, CObject>
{
public:
  void foo() { cout << "CObject" << endl; };
};

To specialize member function in Visual C++ 2008 you could make it template too:

template<typename A, typename B>
class C
{
  template<typename T>
  void foo();

  template<>
  void foo<CObject>();
};

The solution above seems to will be available only in future C++ Standard (according to draft n2914 14.6.5.3/2).

5
  • While the second is correct, the first is wrong - you cannot put explicit specializations in class scope - and even if you put the specialization of the template in namespace scope - if you specialize a template, then all its enclosing templates have to be specialized too :( So you have to stick with the second way. Commented Oct 8, 2009 at 15:37
  • So this won't work for example: template<typename A, typename B> template<> void C<A, B>::foo<CObject>() { }, because while the member function template is specialized, the outer one isn't yet. You could do the other way around though template<> template<typename T> void C<int, bool>::foo() { } but i suspect this isn't what he wants to do -.- Commented Oct 8, 2009 at 15:44
  • First seems to be not C++03 Standard compliant, but it works in Visual C++ 2008. It looks like C++0x extension (14.6.5.3 Members of class template specializations). Commented Oct 8, 2009 at 18:00
  • Fixed answer, second option still there for reference. Commented Oct 8, 2009 at 18:06
  • Well the example in 14.6.5.3/2 in the c++0x draft is a partial specialization. For partial specializations, those restrictions aren't in place. Those can be put in class scope - already in c++03. But in your case, you explicitly specialize the function template. If they had done this in their example, it would be illegal aswell: template<class T> struct A { template<class T2> struct B {}; template<> struct B<int*> {}; }; . There is an issue report at open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#727 asking for lifting this restriction (which i would welcome too, of course) Commented Oct 8, 2009 at 18:39
8

I think there is a misunderstanding there.

There are two kinds of templates:

  • the template classes
  • the template methods

In your example, you have a template class, which of course contains some methods. In this case, you will have to specialize the class.

template <class A>
class C<A,CObject>
{
  void foo() { ... } // specialized code
};

The problem in your example is relatively simple: you define the method foo for the specialization C but this specialization has never been declared beforehand.

The problem here is that you have to fully specialize your C class (and thus copying a lot of data). There are a number of workarounds.

  • Inheritance (Composition ?): do all the common work in a base class, then have the C class inherits and specialize as appropriate
  • Friend: instead of having the 'foo' method being a member of C, define it as a friend free functions and specialize only this method
  • Delegation: have your 'foo' method call another method 'bar', which is a free function, and specialize 'bar' appropriately

Which in code gives:

// 1- Inheritance
template <class A, class B>
class CBase
{
  // Everything that does not require specialization
};

template <class A, class B>
class C: public CBase<A,B>
         // depending on your need, consider using another inheritance
         // or even better, composition
{
  void foo(); // generic
};

template <class A>
class C<A,CObject> : public CBase<A,CObject>
{
  void foo(); // specialized
};

// 2- Friend
// note the change in signature:
// - now you need to pass the attributes to be changed
// - the last parameter helps differentiating the overload
//   as there is no specialization for functions
template <class A, class B> void foo(Arg1&, Arg2&, const B&);
template <class A> void foo(Arg1&, Arg2&, const CObject&);

template <class A, class B>
class C
{
  friend template <class, class> foo;
};

// 3- Delegation
// same signature as foo in (2)
template <class A, class B> void bar(Arg1&, Arg2&, const B&);
template <class A> void bar(Arg1&, Arg2&, const CObject&);

template <class A, class B>
class C
{
  void foo() { bar(member1, member2, B()); }
};

Hope it clarifies, and helps!

2

No, there is no partial function template specialization in C++0x to be added.

As correctly mentioned above, with regards to function templates basically 2 things were done:

  • default template arguments were made available;
  • variadic templates were introduced.

So as before, workarounds should be used to "emulate" partial function templates specialization.

1

Since the class is the template, you need to specialize that:

template <class A>
class C<A, CObject> 
{
   void foo() { ... }
}
1
  • I already specialized class, but I exactly need to specialize method :)
    – faya
    Commented Oct 8, 2009 at 5:53
0

If I remember correctly, you cannot make partial template specialization for functions. Not sure whether it is included in C++0X

Update: (Awaiting confirmation) As noted in the comments, partial template specialization of functions is possible in C++0X.

3
  • This restriction is lifted on C++0x
    – the_drow
    Commented Oct 8, 2009 at 5:59
  • @yngvedh, have you got a reference for that "Update:" note? I haven't heard of this yet. Afaik, they just liften default arguments - i.e you can have default arguments in function templates. Commented Oct 8, 2009 at 15:39
  • @libt, no reference. I just assumed the_drow knew what he was talking about as I'm no expert on C++0X. Can anyone in the know confirm this? I'll update appropriately. Commented Oct 8, 2009 at 19:49
0

A method template may delegate to (static) methods of partially specialized classes or structs. Template parameters in the outer class are not helpful for answering the question.

class ClassWithSpecializedMethodEmulation
{
private:
    template <typename A, typename B> struct Calculator;

public:
    template <typename A, typename B> A evaluate(A a, B b)
    {
        return Calculator<A,B>::evaluate(a,b);
    }

private:
    template <typename A, typename B> struct Calculator
    {
        // Common case: multiply
        static A evaluate(A a, B b)
        {
            return (A)(a*b);
        }
    };

    // with double argument a do something else    
    template <typename B> struct Calculator<double, B>
    {
        static double evaluate(double a, B b)
        {
            return (double)(a - b);
        }
    };
};

In case the method requires access to class members, struct Calculator additionally must be friend of ClassWithSpecializedMethodEmulation and get a this-pointer passed.

Not the answer you're looking for? Browse other questions tagged or ask your own question.