Использование std :: bind и std :: function в обратных вызовах - PullRequest
3 голосов
/ 06 июля 2011

Я пытался понять использование c ++ 0x std :: bind и std :: function при обработке событий / обратных вызовов. Поэтому я изучал некоторые фрагменты кода и обнаружил некоторые интересные места, которые я не могу полностью понять.

Допустим, у нас есть:

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;
}

Вопрос: Какой тип Слушатель содержит в этой части?:

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

Поскольку в основном методе мы вызываем эту функцию только с помощью.

PS: также этот код не выполняется в части std :: is_convertible. (как я понимаю, из-за несоответствия типов из habindEvent<KeyboardEvent> (&do_key);

Ответы [ 2 ]

6 голосов
/ 06 июля 2011

Listener будет выведен компилятором как тип указателя на функцию, которую вы передаете ему, в этом случае void(const KeyboardEvent&).

И ваш тест не пройден, потому что все наоборот: вы хотите

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

(обратите внимание на отрицание).

Кстати, и std::is_array, и std::is_convertable определяются во время компиляции, что означает, что вы используете среду выполненияпроверить на то, что определено статически.Вместо этого вы можете сделать так, чтобы шаблон не связывался с недопустимыми типами, используя 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)
{
}

Это вызовет ошибку компилятора, если вы попытаетесь создать экземпляр шаблона с типами, которые не соответствуют вашим условиям.

1 голос
/ 06 июля 2011

Ну, во-первых, я предполагаю, что habindEvent<KeyboardEvent> (&do_key); является опечаткой и должно быть handler.bindEvent<KeyboardEvent>(&do_key).

Таким образом, тип слушателя - это шаблонное вычитание из параметра. Так что в вашем особом случае это будет так.

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

Но вам не нужен Fn_t, так как компилятор может сделать эту работу за вас.
И после исправления вашего типа код компилируется на моей машине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...