Search code examples
c++c++11std-functionstdbind

Bind std::function error


I face a problem when trying to bind a method with std::function and std::bind.

In my CommunicationService class :

this->httpServer->BindGET(std::bind(&CommunicationService::ManageGETRequest, this, std::placeholders::_1));

CommunicationService::ManageGetRequest signature :

MessageContent CommunicationService::ManageGetRequest(std::string uri, MessageContent msgContent)

BindGET signature :

void RESTServer::BindGET(RequestFunction getMethod)

RequestFunction typedef :

typedef std::function<MessageContent(std::string, MessageContent)> RequestFunction;

The error on BindGET :

error C2664: 'void RESTServer::BindGET(RequestFunction)': cannot convert argument 1 from 'std::_Binder < std::_Unforced,MessageContent (__cdecl communication::CommunicationService::* )(std::string,MessageContent),communication::CommunicationService *const ,const std::_Ph < 1 > & >' to 'RequestFunction'

Before, my RequestFunction was like that :

typedef std::function<void(std::string)> RequestFunction;

and it worked perfectly. (with all signature methods adjusted of course).

I don't understand what causes the error.


Solution

  • Change

    this->httpServer->BindGET(
      std::bind(&CommunicationService::ManageGETRequest, this, std::placeholders::_1)
    );
    

    to

    this->httpServer->BindGET(
      [this](std::string uri, MessageContent msgContent) {
        this->ManageGETRequest(std::move(uri), std::move(msgContent));
      }
    );
    

    Using std::bind is almost always a bad idea. Lambdas solve the same problems, and almost always do it better, and give better error messages. The few cases where std::bind has features lambdas do not where mostly covered by C++14.

    std::bind was written in pre-lambda C++11 as boost::bind then brought into the standard at the same time lambdas where. At the time, lambdas had a few limitations, so std::bind made sense. But this isn't one of the cases where lambdas C++11 limitations occur, and as lambda has grown in power since, learning to use std::bind has significantly diminished marginal utility at this point.

    Even if you master std::bind, it has enough annoying quirks (like passing a bind expression to bind) that avoiding it has payoff.

    You could also fix it with:

    this->httpServer->BindGET(
      std::bind(&CommunicationService::ManageGETRequest, this, std::placeholders::_1, std::placeholders::_2)
    );
    

    but I don't think you should.