开发者

std::bind and std::function usage in callbacks

I was trying to understand c++0x std::bind and std::function usage in event handling / callbacks. So I was examining some code snippets and encountered some interesting places which I can't fully understand.

Let's say we have:

class EventHandler
{
public:
    template<typename Event, typename Listener>
    bool bindEvent (const Listener& function)
    {
        if (std::is_array<Event>::value)
        {
            std::cout << "You cannot register an array as an event type" << std::endl;
  开发者_运维问答          return false;
        }
        if (std::is_convertible<Listener, std::function<void (Event&)>>::value)
        {
            std::cout << "Invalid callback for this event type" << std::endl;
            return false;
        }

        listeners.insert(std::make_pair(&typeid(typename std::decay<Event>::type),
                           [=](void* ev) { function(*static_cast<Event*>(ev)); }));
    }
private:
    // for each event type, we have a list of callbacks
    // these callbacks are of the form std::function<void (void*)>
    // because we will convert between the &event and void*
    typedef std::function <void (void*)> fun;
    std::unordered_multimap <const std::type_info*, fun> listeners;
};

// example of an event type
struct KeyboardEvent
{
    int keyCode;
};

// example of an event callback
void do_key (const KeyboardEvent &event)
{
    std::cout << "I am working" << std::endl;
}

int main (int argc, char** argv)
{
    EventHandler handler;
    handler.bindEvent<KeyboardEvent> (&do_key);   // fixed typo

    return 0;
}

Question: What type does Listener holds in this part ?:

template<typename Event, typename Listener>
bool bindEvent(const Listener& function)

Since in main method we call this function only with .

PS: Also, this code fails in std::is_convertible part. (as I understand, because of mismatch type from habindEvent<KeyboardEvent> (&do_key);


Listener will be inferred by the compiler to be the type of function pointer that you pass it, in this case void(const KeyboardEvent&).

And your test fails because it's the wrong way around: you want

if (!std::is_convertible<Listener, std::function<void (Event&)>>::value)

instead (note the negation).

By the way, both std::is_array and std::is_convertable are decided at compile time, which means that you are using a run-time check for something that is statically determined. Instead, you can make the template fail to bind for invalid types using SFINAE:

template<typename Event, typename Listener>
typename std::enable_if<!std::is_array<Event>::value && std::is_convertible<Listener, std::function<void(Event&)>>::value, bool>::type bindEvent (const Listener& function)
{
}

This will cause a compiler error if you try to instantiate the template with types that don't match your conditions.


Well first I assume that habindEvent<KeyboardEvent> (&do_key); is a typo and should be handler.bindEvent<KeyboardEvent>(&do_key).

So the type of the listener is a template deduction from the parameter. So in your special case it would be this.

typedef void(*Fn_t)(const KeyboardEvent &);
EventHandler handler;
handler.bindEvent<KeyboardEvent, Fn_t> (&do_key);

But you don't need the Fn_t since the compiler can do this work for you.
And after fixing your type the code compiles on my machine.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜