简体   繁体   English

回调中的 std::bind 和 std::function 用法

[英]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.我试图了解 c++0x std::bind 和 std::function 在事件处理/回调中的用法。 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?:问题: Listener在这部分中持有什么类型?:

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

Since in main method we call this function only with.由于在 main 方法中,我们仅将其称为 function。

PS: Also, this code fails in std::is_convertible part. PS:此外,此代码在 std::is_convertible 部分失败。 (as I understand, because of mismatch type from habindEvent<KeyboardEvent> (&do_key); (据我了解,由于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&) . Listener将被编译器推断为您传递给它的 function 指针的类型,在本例中为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.顺便说一句, std::is_arraystd::is_convertable都是在编译时决定的,这意味着您正在对静态确定的东西使用运行时检查。 Instead, you can make the template fail to bind for invalid types using SFINAE:相反,您可以使用 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);首先我假设habindEvent<KeyboardEvent> (&do_key); is a typo and should be handler.bindEvent<KeyboardEvent>(&do_key) .是一个错字,应该是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.但是您不需要 Fn_t,因为编译器可以为您完成这项工作。
And after fixing your type the code compiles on my machine.在修正你的类型之后,代码会在我的机器上编译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM