Roberto
Roberto

Reputation: 1351

Overloading c++ template class method

Can I overload a template class function in a class that extends its specialization?

I have the following piece of code (I've tried to simplify it to the bare minimum):

#include <iostream>

using namespace std;

class X {
 public:
  unsigned test_x() {
    return 1;
  }
};

class Y {
 public:
  unsigned test_y() {
    return 2;
  }
};

template <typename T, typename U>
class A {

 public: 

  unsigned foo(U i) {
    cout << "A" << endl;   
    return i.test_x();
  }

  unsigned bar(T i) {
    return foo(i);
  }

};

class B : public A<Y, X> {
 public:
  unsigned foo(Y i) {
    cout << "B" << endl;   
    return i.test_y();
  }
};

int  main() {

  B b = B();
  Y y = Y();
  cout << "Hello: " << b.bar(y) << endl;   
  return 0;

}

However the compiler produces the following error:

hello.cc: In member function ‘unsigned int A<T, U>::bar(T) [with T = Y, U = X]’:
hello.cc:47:   instantiated from here
hello.cc:30: error: no matching function for call to ‘A<Y, X>::foo(Y&)’
hello.cc:24: note: candidates are: unsigned int A<T, U>::foo(U) [with T = Y, U = X]

Basically I would like to overload the function A::foo() in its derived class B.

Upvotes: 3

Views: 5531

Answers (3)

Yakov Galka
Yakov Galka

Reputation: 72539

Apparently what you're asking is called "static polymorphism" and it's achieved by the means of "curiously recurring template pattern":

template <typename Derived, typename T, typename U>
class A {
 public:

  unsigned foo(U i) {
    cout << "A" << endl;   
    return i.test_x();
  }

  unsigned bar(T i) {
    return static_cast<Derived*>(this)->foo(i);
  }

};

class B : public A<B, Y, X> {
 public:
  // Uncomment this line if you really want to overload foo
  // instead of overriding. It's optional in this specific case.
  //using A::foo; 

  unsigned foo(Y i) {
    cout << "B" << endl;   
    return i.test_y();
  }
};

Upvotes: 6

WolfgangP
WolfgangP

Reputation: 3233

Edit: My first answer was incorrect.

When you instantiate A with classes Y and X the call of foo(T) generates an error because there no proper overloaded method defined in A. It suffices to declare a pure virtual method of foo(T) in A and implement this method in B.

template <typename T, typename U>
class A {
public: 
  virtual unsigned foo(T i) = 0;
  unsigned foo(U i) { /* as above */ }
  unsigned bar(T i) {
    return foo(i); // calls abstract foo(T)
  }
};
/* B is left untouched */

Compiling this generates this output:

B
Hello: 2

Upvotes: 0

UncleBens
UncleBens

Reputation: 41351

I don't think the overloads in derived classes cannot be used from the base class where they are to be called from.

What you can do, is to extract the foo method, so you can specialize it for B.

#include <iostream>

using namespace std;

class X {
 public:
  unsigned test_x() {
    return 1;
  }
};

class Y {
 public:
  unsigned test_y() {
    return 2;
  }
};

template <typename T, typename U>
struct Foo
{
    unsigned foo(U i) {
    cout << "A" << endl;
    return i.test_x();
  }
};

template <typename T, typename U>
class A : public Foo<T, U> {

 public:
  unsigned bar(T i) {
    return this->foo(i);
  }
};

template <>
struct Foo<Y, X>
{
 public:
  unsigned foo(Y i) {
    cout << "B" << endl;
    return i.test_y();
  }
};

class B : public A<Y, X> {
};

int  main() {

  B b = B();
  Y y = Y();
  cout << "Hello: " << b.bar(y) << endl;
  return 0;
}

Upvotes: 0

Related Questions