0

I found that I can't move an Asio socket object boost::asio::ip::tcp::socket&& to a lambda for the boost::asio::write() function. I trim the case into a test program below in order to try the compiler results.

If I uncomment the boost::asio::write(sock,... line, both clang and gcc blamed that there is no sock.write_some() method... but boost::asio::ip::tcp::socket::write_some() is available from the library!

The test code:

// to build:
// clang++ -Wall -std=c++17 -o test_asio_lambda_clang test_asio_lambda.cpp
// g++-9 -Wall -std=c++17 -o test_asio_lambda_gcc test_asio_lambda.cpp

#include<boost/asio.hpp>
#include<iostream>
#include<type_traits>

int main()
{
  auto foo=[](boost::asio::ip::tcp::socket s){
    auto bar=[&s,sock{std::move(s)}](){

      std::cout<<"std::is_same<decltype(sock),decltype(s)>::value = "<<std::is_same<decltype(sock),decltype(s)>::value<<std::endl;
      std::cout<<"std::is_same<decltype(sock),boost::asio::ip::tcp::socket>::value = "<<std::is_same<decltype(sock),boost::asio::ip::tcp::socket>::value<<std::endl;

      //boost::asio::write(sock,boost::asio::buffer(std::string{"Hello, folk!\n"}));
    };


    bar();
  };

  boost::asio::io_context io_context;
  boost::asio::ip::tcp::socket sock{io_context};
  foo(std::move(sock));
}

So, I comment out this line and check the type using std::is_same to test the type as I think that the type of sock and s should be sort of boost::asio::ip::tcp::socket and the code boost::asio::write(sock,...) should compile.

The result of clang and gcc are different!

I have no idea what's wrong... my coding problem, compiler error, boost.asio error?

$ ./test_asio_lambda_clang 
std::is_same<decltype(sock),decltype(s)>::value = 1
std::is_same<decltype(sock),boost::asio::ip::tcp::socket>::value = 1
$ ./test_asio_lambda_gcc
std::is_same<decltype(sock),decltype(s)>::value = 0
std::is_same<decltype(sock),boost::asio::ip::tcp::socket>::value = 0

1 Answers1

2

boost::asio::write takes sock by non-const reference. It means that sock is affected by this function.

sock is data member of closure generated by lambda. By default, function call operator of closure is marked as const. So you are allowed only to pass sock to other const functions.

If you want to let lambda modify sock you have to add mutable keyword:

auto bar=[&s,sock{std::move(s)}]() mutable {
rafix07
  • 20,001
  • 3
  • 20
  • 33
  • Thank you! That's why the compiler complains no write_some() as it is not const. BTW, regarding asio programming, its better to use lambda or `std::bind`? – Victor Tsang May 08 '20 at 13:10
  • @VictorTsang It is hard to say which one is better. They both do the same job. [Under this link](https://stackoverflow.com/questions/17363003/why-use-stdbind-over-lambdas-in-c14/17545183) is nice summary about *bind vs lambda*, it doesn't strictly concern a use in Asio, but it is worth reading. – rafix07 May 08 '20 at 13:57