I’m trying to code the following situation:
I have a base class providing a framework for handling events. I’m trying to use an array of pointer-to-member-functions for that. It goes as following:
class EH { // EventHandler
virtual void something(); // just to make sure we get RTTI
public:
typedef void (EH::*func_t)();
protected:
func_t funcs_d[10];
protected:
void register_handler(int event_num, func_t f) {
funcs_d[event_num] = f;
}
public:
void handle_event(int event_num) {
(this->*(funcs_d[event_num]))();
}
};
Then the users are supposed to derive other classes from this one and provide handlers:
class DEH : public EH {
public:
typedef void (DEH::*func_t)();
void handle_event_5();
DEH() {
func_t f5 = &DEH::handle_event_5;
register_handler(5, f5); // doesn't compile
........
}
};
This code wouldn’t compile, since DEH::func_t cannot be converted to EH::func_t. It makes perfect sense to me. In my case the conversion is safe since the object under this is really DEH. So I’d like to have something like that:
void EH::DEH_handle_event_5_wrapper() {
DEH *p = dynamic_cast<DEH *>(this);
assert(p != NULL);
p->handle_event_5();
}
and then instead of
func_t f5 = &DEH::handle_event_5;
register_handler(5, f5); // doesn't compile
in DEH::DEH()
put
register_handler(5, &EH::DEH_handle_event_5_wrapper);
So, finally the question (took me long enough…):
Is there a way to create those wrappers (like EH::DEH_handle_event_5_wrapper) automatically?
Or to do something similar?
What other solutions to this situation are out there?
Thanks.
Instead of creating a wrapper for each handler in all derived classes (not even remotely a viable approach, of course), you can simply use
static_castto convertDEH::func_ttoEH::func_t. Member pointers are contravariant: they convert naturally down the hierarchy and they can be manually converted up the hierarchy usingstatic_cast(opposite of ordinary object pointers, which are covariant).The situation you are dealing with is exactly the reason the
static_castfunctionality was extended to allow member pointer upcasts. Moreover, the non-trivial internal structure of a member function pointer is also implemented that way specifically to handle such situations properly.So, you can simply do
I would say that in this case there’s no point in defining a typedef name
DEH::func_t– it is pretty useless. If you remove the definition ofDEH::func_tthe typical registration code will look as followsTo make it look more elegant you can provide a wrapper for
register_handlerinDEHor use some other means (a macro? a template?) to hide the cast.This method does not provide you with any means to verify the validity of the handler pointer at the moment of the call (as you could do with
dynamic_castin the wrapper-based version). I don’t know though how much you care to have this check in place. I would say that in this context it is actually unnecessary and excessive.