c++functionboostboost-bind

Using boost:bind to bind a std::function


I have a problem using boost::bind with a function stored into std::function.

This is related to boost::asio: I am building a basic UDP server. So, first lets see some code that compiles fine without std::function (whole code on Coliru here, uncomment the define to see the problem):

Here only the relevant part:

class udp_server
{
        void start_receive()
        {
            _socket.async_receive_from(
                boost::asio::buffer( _buffer ),
                _remote_endpoint,
                boost::bind(
                    &udp_server::_rx_handler,
                    this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred,
                    42
                )
            );
        }

        void _rx_handler( const boost::system::error_code&, std::size_t bytes_rx, int );
};

As you can see, I am passing the handler _rx_handler (aka "callback") to the boost::asio function, so that when something gets received, the function will be called. As I need a third argument and the "asio" function requires a specific function signature, I am using boost::bind. So far so good.

Now, I want to inherit this class into another one, where I can define some more specific things to do upon receiving data. So I replace in base class the handler with a std::function, with same signature:

std::function< void( const boost::system::error_code&, std::size_t bytes_rx, int )> _rx_handler;

or, more conveniently, using a typedef;

typedef std::function< void( const boost::system::error_code&, std::size_t bytes_rx, int ) > CALLBACK_T;
...
CALLBACK_T _rx_handler;

That way (I thought), I can add a member function to assign any member function from an inherited class:

void assignCallback( CALLBACK_T f )
{
    _rx_handler = f;
}

Unfortunately, this does not compile. GCC 5.4.1 says:

/usr/include/boost/bind/bind.hpp:69:37: error: ‘std::function udp_server::*’ is not a class, struct, or union type

But when I check cppreference, I read that it is a class template...

After looking at this page, I also tried to access the pointer on function with target():

boost::bind(
    &udp_server::_rx_handler.target(),
    this,
    boost::asio::placeholders::error,
    boost::asio::placeholders::bytes_transferred,
    42
)

but this does not compile either:

error: no matching function for call to ‘std::function::target()’ udp_server::_rx_handler.target(),

Question: What is wrong here? I thought a "real" function and std::function were interchangeable? How can I make this work?

Addendum: I have the feeling that this is possibly related to my lack of knowledge on how the whole binding thing works, so thanks for any insights!

Possibly related: std::function and std::bind: what are they & when they should be used?


Solution

  • Your binding should be modified as follow:

    void start_receive()
    {
        _socket.async_receive_from(
            boost::asio::buffer( _buffer ),
            _remote_endpoint,
            boost::bind(
                udp_server::_rx_handler,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred,
                42
            )
        );
    }
    

    You change _rx_handler from void (udp_server::*)(const boost::system::error_code&, std::size_t bytes_rx, int); to std::function<void(const boost::system::error_code&, std::size_t bytes_rx, int)>

    So you no longer have to bind to an instance to udp_server.