c++11boostlambdaboost-asiobeast-websockets

How to use boost::aio::async_connect with lambda


I want to reliaze how to use boost::aio::async_connect with lambda. Boost version 1.68

It's really strange that I could use std::bind but not lambda. If I use std::bind, it work. But when I use lambda, it buillt failed, and said "IteratorConnectHandler type requirements not met.

std::bind version (worked)

void SslClient::connect(boost::asio::ip::tcp::resolver::results_type results) {
    auto sp = shared_from_this();
    boost::asio::async_connect(ws->next_layer().next_layer(),
        results.begin(),
        results.end(),
        std::bind(
            on_connect,
            std::placeholders::_1)

    );
}

lambda version (not worked)

void SslClient::connect(boost::asio::ip::tcp::resolver::results_type results) {
    auto sp = shared_from_this();
    boost::asio::async_connect(ws->next_layer().next_layer(),
        results.begin(),
        results.end(),
            [&, sp](boost::system::error_code ec) {
               if (ec) {
                   return;
               }
               ws->next_layer().async_handshake(boost::asio::ssl::stream_base::client,
                                                [&, sp](boost::system::error_code ec1) {
                                                    handShake(ec);
                                                });
        }


    );
}

So how to use lambda here?


Solution

  • You call async_connect with pair of iterators, so your lambda should meet iterator connect handler requirements. As second parameter you have to pass connected endpoint.

    boost::asio::async_connect(ws->next_layer().next_layer(),
        results.begin(),
        results.end(),
            [&, sp](  boost::system::error_code ec,
                      boost::asio::ip::tcp::resolver::iterator it) 
               {
               if (ec) {
                   return;
               }
               //...
    

    To be consistent with reference you should also fix bind version. on_connect should also take iterator as second param.

    Your current bind version compiles and works, but when asynchronous operation initiated by async_connect is completed, functor created by bind is called with only error_code, you cannot access endpoint. You can modify bind so that it takes on_connect without any arguments.

    void on_connect(){}
    
    boost::asio::async_connect(ws->next_layer().next_layer(),
            results.begin(), results.end(), std::bind(on_connect)); // compiles fine
    

    this also compiles, but when handler is called neither error_code nor endpoint can be accessed. (Yes it is a bit strange that you are not getting compiler errors when using bind which inform that requirements of handler are not fulfilled. I don't know where this disagreement between lambda and bind comes from.)