I am trying to create a generic "callback" object that will hold arbitrary data and invoke member functions of related classes. Due to internal policy, I cannot use Boost.
The callback object looks like this:
template<typename Object, typename Data>
class Callback
{
public:
typedef void (Object::*PHandler)(Callback*);
Callback(Object* obj, PHandler handler) : pObj(obj), pHandler(handler) {}
Callback& set(PHandler handler) { pHandler = handler; return *this; }
void run() { (pObj->*pHandler)(this); }
public:
Data data;
protected:
Object* pObj;
PHandler pHandler;
};
And the class it works on:
struct Object1
{
struct Data { int i; };
typedef Callback<Object1, Data> Callback1;
void callback(Callback1* pDisp) { printf("%cb\n", pDisp->data.i); }
void test()
{
Callback1 cb(this, &Object1::callback);
cb.data.i = 1;
cb.run();
}
};
The following test works as expected:
Object1 obj1;
obj1.test();
So far so good.
However, when a coworker tried to derive from the Callback
class instead of using a typedef
, they got compilation errors due to incompatible pointers:
struct Object2
{
struct Data { int i; Data(int j) { i = j; } };
class Callback2 : public Callback<Object2, Data>
{
Callback2(Object2* obj, PHandler handler, int i) : Callback(obj, handler) { data.i = i; }
};
void callback(Callback2* pDisp) { printf("%cb\n", pDisp->data.i); }
void test()
{
Callback2 cb(this, &Object2::callback, 2);
cb.run();
}
};
I tried using the "curiously recurring template pattern" in the Callback class and managed to get derived classes working, but it broke code that used the typedef
method.
My question is:
How can I modify the Callback
class to work with both cases, and without requiring extra work on the part of the user of the class?
Thank you.