Search code examples
c++c++11stdbind

How to use std::bind for adding member callback to a messenger system


I am currently trying to implement a messenger system for my game engine. It uses function callbacks of the form:

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

I want all objects to be able to subscribe to a message of a specific type (where the type is just a string). Subscribing means adding their "onEvent" function to the dictionary of callbacks.

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

The update function then calls these functions and passes the according message (from which the "onEvent" functions can get their data)

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

Now, my problem is that I am not quite sure how to bind these "onEvent" functions. I have just recently switched to C++11 and the concept of function objects and std::bind is quite new to me. So here is what I have tried:

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

where the ClickableComponent::OnClick function has the required signature:

void OnClick(const Message &);

and the Subscribe function just adds the passed function to the dictionary

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

(The push_back is used because there is a vector of callbacks for each type)

The code seems fine to me but the line:

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

Gives me the error: picture of the error discription

I have tried all kinds of stuff like forwarding the Messenger reference and using placeholders, but I have the feeling that I am doing something else wrong. Also, better idea on how to implement this messenger system are appreciated ^^

Thanks for your help!


Solution

  • std::bind is not necessary in your case, lambda function would do just fine:

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

    std::bind is more useful in specific cases of metaprogramming.

    But if you're curios enough to see how to use std::bind:

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

    Here, as you see, you missed std::placeholders::_1. Your functor signature is void(const Message&), but you try to store a member function which signature can be regarded as void(ClickableComponent*, const Message&). To partially apply some arguments (what std::bind does) you need to specify arguments that you'd like to bind and arguments that you leave unbound.

    Lambda is preferred because usually it's shorted, more flexible and more readable.