Implicit casting for method handler?
Some code
typedef void (*EventHandler) (EventObject* sender, EventArgs* args, void* closure);
class Control
{
void AddHandler(int eventId, EventHandler handler, void* data)
}
class SubControl
{
static void mousemove_cb(EventObject* sender, MouseEventArgs* calldata, void* closure);
}
The error
error C2664: 'Control::AddHandler' : cannot convert parameter 2 from 'void (__cdecl *)(EventObject *,MouseEventArgs *,void *)' to 'EventHandler'
Here is the line that produce the error:
control.AddHandler(MouseMoveEvent, mous开发者_如何学Cemove_cb, 0);
Description
The problem is that MouseEventArgs is a sub-class of EventArgs ! So, is there a way to have an automatic casting and register my method with the precise 'Event args'?
C++ template could solve this problem. Use this:
struct Control
{
//Note this change!
template<typename TEventHandler>
void AddHandler(int eventId, TEventHandler handler, void* data);
};
struct SubControl
{
static void mousemove_cb(EventObject* sender, MouseEventArgs* calldata, void* closure);
SubControl()
{
Control control;
control.AddHandler(0, mousemove_cb, 0);
}
};
You get the error because it's actually forbidden by the language. If it had been possible this would open a hole in the type system. Consider this code:
struct EventArgs {};
void f(EventHandler handler)
{
EventArgs args;
handler(0, &args, 0);
}
struct MouseEventArgs : EventArgs { void GetMousePosition(); };
void g(EventObject* sender, MouseEventArgs* args, void* closure)
{
args->GetMousePosition();
}
f(g); // oops... g calls GetMousePosition on EventArgs
Fortunately the compiler catches this bug.
No, there is no automatic cast. Types have to coincide. You can change the signature to the AddHandler
in two different ways:
- Set it to accept a
void*
and then do force the conversion to the exact pointer to function type. - Convert the
AddHandler
into a template that accepts a typeT
so that it can be called with the correct parameters,t(sender, args,...)
, where the second parameter is the arguments. However, the call has to convert first theargs
to the correct type (for example, if it is a mouse event, convert it toMouseEventArgs
manually before callingt
.
精彩评论