27

Say I have a templated class like

template <typename T> struct Node
{
    // general method split
    void split()
    {
        // ... actual code here (not empty)
    }
};

Need to specialise this in the Triangle class case.. something like

template <>
struct Node <Triangle*>
{
    // specialise the split method
    void split() {}
} ;

but I don't want to rewrite the entire template over again! The only thing that needs to change is the split() method, nothing more.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
bobobobo
  • 64,917
  • 62
  • 258
  • 363

4 Answers4

31

You can provide a specialization for only that function outside the class declaration.

template <typename T> struct Node
{
    // general method split
    void split()
    {
        // implementation here or somewhere else in header
    }
};

// prototype of function declared in cpp void splitIntNode( Node & node );

template <>
void Node<int>::split()
{
     splitIntNode( this ); // which can be implemented
}

int main(int argc, char* argv[])
{
   Node <char> x;
   x.split(); //will call original method
   Node <int> k;
   k.split(); //will call the method for the int version
}

If splitIntNode needs access to private members, you can just pass those members into the function rather than the whole Node.

CashCow
  • 30,981
  • 5
  • 61
  • 92
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    Really? I didn't think this was possible. – Lightness Races in Orbit Feb 17 '12 at 15:14
  • @LightnessRacesinOrbit code sample added, I couldn't remember the exact syntax and wanted to test it first. – Luchian Grigore Feb 17 '12 at 15:15
  • 1
    @LightnessRacesinOrbit : I didn't either ... learned something new +1 :-) – Jason Feb 17 '12 at 15:15
  • BTW, does this only work for full specializations, or can it work for partial specializations as well? – Jason Feb 17 '12 at 15:16
  • @Jason beats me... one way to find out :). Well, actually two, but checking the standard isn't as fun as trying it out. – Luchian Grigore Feb 17 '12 at 15:18
  • Very nice. I also tried declaring `template void split() { }` inside `struct Node` and it worked, but this way is cleaner – bobobobo Feb 17 '12 at 15:19
  • 1
    Looks like [my attempts](http://ideone.com/IGvO7) at partial specialization aren't working whereas the [fully-specialized](http://ideone.com/q0AWh) version does ... :( – Jason Feb 17 '12 at 15:21
  • Wait, my previous comment _doesn't_ work, it only compiles (`template void split() { }`). [See next question](http://stackoverflow.com/questions/9331036/what-is-this-template-specialization-code-doing-and-why-does-it-compile-but-n) – bobobobo Feb 17 '12 at 15:33
  • @bobobobo also an interesting question :) – Luchian Grigore Feb 17 '12 at 15:34
  • And if you want to hide the implementation of the specialised function, i.e. you want to put it in a compilation unit, the best way is to just create "stubs" of the implementation you want to call and put that in the compilation unit. – CashCow Dec 10 '14 at 11:07
9

Your case is a fortunate example because you are fully-specializing the template. In other words there is only one template argument, and for the function you wish to specialize, you are providing a fully-specialized instantiation of that function definition. Unfortunately for partial class template specialization, it is a requirement that you re-implement the class.

For example, this works:

template<typename T, typename U>
struct Node
{
    void function() { cout << "Non-specialized version" << endl; }
};

template<>
void Node<int, char>::function() { cout << "Specialized version" << endl; }

The partially specialized version though will not work:

template<typename T, typename U>
struct Node
{
    void function() { cout << "Non-specialized version" << endl; }
};

template<typename U>
void Node<int, U>::function() { cout << "Specialized version" << endl; }

What you may want to-do if you find yourself in the second scenario, in order to avoid the needless duplication of code, is pack all the common elements into a common base-class, and then place all the elements that will be varying with the partial specialization in a derived class. That way you do not need to reduplicate all the common code in the base-class, you would only need to re-write the definitions for the specialized derived class.

Jason
  • 31,834
  • 7
  • 59
  • 78
6

Just define some

template<>
void Node<Triangle*>::split()
{
}

after the primary template, but before the first time you ever instantiate it.

PlasmaHH
  • 15,673
  • 5
  • 44
  • 57
2

Awkward method that I usually use: Declare a "basic" template implementation. Then declare your template implementation, the default implementation would just inherit the "basic" one. The customize would inherit the "basic", plus override specific methods. Like this:

template <typename T> struct NodeBase
{
    // methods
};

template <typename T> struct Node
    :public NodeBase<T>
{
    // nothing is changed
};

template <> struct Node<SpecificType>
    :public NodeBase<SpecificType>
{
    // re-define methods you want
};

Note that the "method overriding" has nothing to do with virtual functions or etc. It's just a declaring a function with the same name and parameters as in the base - the compiler will automatically use it.

valdo
  • 12,632
  • 2
  • 37
  • 67
  • I've always done it this way, but I can see from the other answers that if it's just a class method, this isn't necessary ... you learn something new every day! – Jason Feb 17 '12 at 15:14