views:

77

answers:

3

Okay, sample code first; this is my attempt at communicating what it is that I'm trying to do, although it doesn't compile:

#include <iostream>

template <class T>
class Base
{
public:
 virtual void my_callback() = 0;
};

class Derived1
 : public Base<int>
 , public Base<float>
{
public:
 void my_callback<int>()
 {
  cout << "Int callback for Derived1.\n";
 }
 void my_callback<float>()
 {
  cout << "Float callback for Derived\n";
 }
};

class Derived2
 : public Base<int>
 , public Base<float>
{

public:
 void my_callback<int>()
 {
  cout << "Int callback for Derived2.\n";
 }
 void my_callback<float>()
 {
  cout << "Float callback for Derived2\n";
 }

};

int main()
{
 {
  Derived1 d;
  Base<int> * i_p = d;
  Base<float> * i_f = d;

  i_p->my_callback();
  i_f->my_callback();
 }
 {
  Derived2 d;
  Base<int> * i_p = d;
  Base<float> * i_f = d;

  i_p->my_callback();
  i_f->my_callback();
 }

 //Desired output:
 // Int callback for Derived1.
 // Float callback for Derived1
 // Int callback for Derived2.
 // Float callback for Derived2
 system("Pause");
}

So, what I'm trying to do is to make a sort of wrapper class to inherit from that will automatically connect the derived class to various callback lists; it needs to connect a specific instance of the derived class to the list, and I want the "user" to have / get to make the callback functions as part of making the derived class, as you can see.

It seems like this should be able to work, although I may need to use a different syntax. If it can't work, do you have any suggestions?

+1  A: 

Yes, you can make this work:

#include <iostream>
using namespace std;

template <class T>
class Base
{
public:
  virtual void my_callback() = 0;
};

class Derived1 : public Base<int>, public Base<float>
{
public:
  void Base<int>::my_callback() {
    cout << "Int callback for Derived1.\n";
  }
  void Base<float>::my_callback() {
    cout << "Float callback for Derived\n";
  }
};

class Derived2 : public Base<int>, public Base<float>
{
public:
  void Base<int>::my_callback() {
    cout << "Int callback for Derived2.\n";
  }
  void Base<float>::my_callback() {
    cout << "Float callback for Derived2\n";
  }
};

int main()
{
  {
    Derived1 d;
    Base<int> * i_p = &d;
    Base<float> * i_f = &d;
    i_p->my_callback();
    i_f->my_callback();
  }
  {
    Derived2 d;
    Base<int> * i_p = &d;
    Base<float> * i_f = &d;
    i_p->my_callback();
    i_f->my_callback();
  }
}

Output:

Int callback for Derived1.
Float callback for Derived
Int callback for Derived2.
Float callback for Derived2
Hans Passant
This does not compile (gcc). Your declarations of Derived::my_callback can not work like that.
frunsi
This works for me; of note, I am using Visual Studio 2008, which I know has some features that aren't standard. Thanks!
Narfanator
Yeah, this is a side-effect of support for explicit interface implementation. You'll be okay as long as you can stick with MSVC.
Hans Passant
+1  A: 

What you want is not possible.

You could add template specializations, though I do not know if this really helps:

template <class T>
class Base {
public:
  virtual void my_callback() = 0;
};

template <>
class Base<int> {
public:
  virtual void my_callback() {
    cout << "Base<int>::my_callback()\n";
  }
};

template <>
class Base<float> {
public:
  virtual void my_callback() {
    cout << "Base<float>::my_callback()\n";
  }
};

class Derived1 : public Base<int>, public Base<float> {
public:
  // NOTE: no my_callback() implementation here
};

class Derived2 : public Base<int>, public Base<float> {
public:
  virtual void my_callback() {
    cout << "Derived2::my_callback()\n";
  }
};


int main()
{
  {
    Derived1 d;
    Base<int> * i_p = &d;
    Base<float> * i_f = &d;
    i_p->my_callback();
    i_f->my_callback();
  }
  {
    Derived2 d;
    Base<int> * i_p = &d;
    Base<float> * i_f = &d;
    i_p->my_callback();
    i_f->my_callback();
  }
}

Output:

Base<int>::my_callback()
Base<float>::my_callback()
Derived2::my_callback()
Derived2::my_callback()

Let me try to explain why:

Derived1 d;
Base<int> * i_p = &d;
Base<float> * i_f = &d;

// will check the vtable, and will call
//  either Derived1::my_callback
//  OR Base<int>::my_callback
i_p->my_callback();

// will check the vtable, and will call
//  either Derived1::my_callback
//  OR Base<float>::my_callback
i_f->my_callback();

Though through the vtable there are two versions of my_callback() in class Derived1, you CAN NOT override either of them, you can only override both at once (like Derived2 does in the example)!

You should just provide two methods "my_callback1()" and "my_callback2()".

frunsi
A: 

Doesn't virtuality associated with template raises an alarm in your head ? ;)

You have to choose your side, either the static, or the dynamic one.

Aurélien Vallée