开发者

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:

  1. Set it to accept a void* and then do force the conversion to the exact pointer to function type.
  2. Convert the AddHandler into a template that accepts a type T 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 the args to the correct type (for example, if it is a mouse event, convert it to MouseEventArgs manually before calling t.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜