Amadeus
Amadeus

Reputation: 10685

Template specialization and inheritance

Suppose I have a template class with a lot of functions and I want to specialize them to change only a few of them and keep the other ones exactly as specified in the base template class.

How can I do that?

Below is what I want to achieve, but the solution isn't good, because it does not allow me to refer to the specialization for int as Base<int> – I need to use IntSpec for that.

#include <iostream>

using namespace std;

template<typename T>
struct Base
{
  void print1() {cout << "Base::print1" << endl;};
  void print2() {cout << "Base::print2" << endl;};
};

struct IntSpec : public Base<int>
{
  void print2() {cout << "Base<int>::print2()" << endl;};
};

int main()
{
  Base<double> d;
  // Base<int> i;  <-- I want this kind of instantiation
  IntSpec i;

  d.print1();
  d.print2();
  i.print1();
  i.print2();
}

The output is:

Base::print1
Base::print2
Base::print1
Base<int>::print2()

Upvotes: 36

Views: 23630

Answers (3)

mfontanini
mfontanini

Reputation: 21910

Nicol's solution works fine, but this is an alternative:

template<typename T>
struct Base
{
  void print1() {cout << "Base::print1" << endl;};
  void print2() {cout << "Base::print2" << endl;};
};

template<>
void Base<int>::print2() {cout << "Base<int>::print2()" << endl;};

That way you can specialize only specific member functions and still use those that you haven't specialized(in this case, print1) without any problem. So now you'd use it just like you wanted:

Base<int> i;
i.print1();
i.print2(); // calls your specialization

Demo here.

Upvotes: 50

tiridactil
tiridactil

Reputation: 389

Another solution would be to add a level of indirection in the function you want to redefine, i.e.

template<typename T>
struct foo
{
    template<typename T2>
    void bar_impl()
    {
        //generic function
    }

    void bar()
    {
        bar_impl<T>();
    }
};

Then you can specialize each function individually for each type or specialize the whole type as wanted.

Upvotes: 4

Nicol Bolas
Nicol Bolas

Reputation: 474436

You just have to use two template classes:

template<typename T>
struct CommonBase
{
  void print1() {cout << "Base::print1" << endl;};
  void print2() {cout << "Base::print2" << endl;};
};

template<typename T>
struct Base : public CommonBase<T>
{
};

template<>
struct Base<int> : public CommonBase<int>
{
  void print2() {cout << "Base::print2" << endl;};
};

You always use Base, rather than CommonBase.

Upvotes: 33

Related Questions