Как использовать std::bind для добавления обратного вызова участника в систему обмена сообщениями

В настоящее время я пытаюсь внедрить систему обмена сообщениями для своего игрового движка. Он использует обратные вызовы функций в форме:

typedef std::function<void(const Message &)> Callback;

Я хочу, чтобы все объекты могли подписаться на сообщение определенного типа (где тип — это просто строка). Подписка означает добавление их функции onEvent в словарь обратных вызовов.

mutable std::map<std::string, std::vector<Callback>> callbackDictionary;

Затем функция обновления вызывает эти функции и передает соответствующее сообщение (из которого функции «onEvent» могут получить свои данные).

for each (auto message in messageList)
{
    // find the list of respective callbacks
    auto it = callbackDictionary.find(message->GetType());

    // If there are callbacks registered for this message type
    if (it != callbackDictionary.end())
    {
        // call every registred callback with the appropreate message
        for each (auto callback in it->second)
            callback(*message);
    }
}

Теперь моя проблема в том, что я не совсем уверен, как связать эти функции «onEvent». Я только недавно перешел на С++ 11, и концепция объектов функций и std::bind для меня совершенно нова. Итак, вот что я пробовал:

messageBus.Subscribe("Message/Click",std::bind(&ClickableComponent::OnClick, this));

где функция ClickableComponent::OnClick имеет требуемую подпись:

void OnClick(const Message &);

а функция Subscribe просто добавляет переданную функцию в словарь

void Messenger::Subscribe(std::string type, Callback callbackFunction) const
{
    callbackDictionary[type].push_back(callbackFunction);
}

(Push_back используется, потому что для каждого типа есть вектор обратных вызовов)

Код кажется мне хорошим, но строка:

messageBus.Subscribe("Message/Click", std::bind(&ClickableComponent::OnClick, this));

Выдает ошибку: изображение описания ошибки

Я пробовал всевозможные вещи, такие как пересылка ссылки на Messenger и использование заполнителей, но у меня такое чувство, что я делаю что-то еще неправильно. Кроме того, приветствуется лучшая идея о том, как реализовать эту систему обмена сообщениями ^^

Спасибо за вашу помощь!


person Adrian Albert Koch    schedule 05.11.2017    source источник
comment
Используйте лямбда-функцию вместо std::bind.   -  person user0042    schedule 05.11.2017
comment
Не используйте for each..in, это нестандартное расширение и больше не нужно. Используйте for (auto x: xs) {}.   -  person Aluan Haddad    schedule 05.11.2017


Ответы (1)


std::bind в вашем случае не требуется, лямбда-функция вполне подойдет:

messageBus.Subscribe("Message/Click", [this](const Message& msg) { OnClick(msg); });

std::bind более полезен в конкретных случаях метапрограммирования.

Но если вам достаточно любопытно, чтобы увидеть, как использовать std::bind:

messageBus.Subscribe("Message/Click", 
    std::bind(&ClickableComponent::OnClick, this, std::placeholders::_1));

Здесь, как видите, вы пропустили std::placeholders::_1. Ваша сигнатура функтора — void(const Message&), но вы пытаетесь сохранить функцию-член, сигнатуру которой можно рассматривать как void(ClickableComponent*, const Message&). Чтобы частично применить некоторые аргументы (что делает std::bind), вам нужно указать аргументы, которые вы хотите связать, и аргументы, которые вы оставите несвязанными.

Lambda предпочтительнее, потому что обычно она короче, более гибкая и более удобочитаемая.

person Andriy Tylychko    schedule 05.11.2017