Search code examples
c++lambdac++17asio

where is the const-ness in this lambda capture argument introduced?


This code compiles correctly.

#include <asio.hpp>
#include <memory>
#include <iostream>

struct Message { int msg; };

// never mind global variables, just for the sake of making this a minimal example
extern asio::ip::tcp::socket mysocket;

void handler(std::shared_ptr<Message> pmsg, asio::error_code error, size_t nbytes);

void readMessage()
{
    std::shared_ptr<Message> pmsg{ new Message };
    asio::async_read(mysocket, asio::buffer(&pmsg->msg, sizeof(int)),
            [pmsg](auto err, auto nbytes) { handler(pmsg, err, nbytes); });
}

However, when I add a reference to the first argument of the handler function

void handler(std::shared_ptr<Message>& pmsg, asio::error_code error, size_t nbytes);

the code no longer compiles, complaining that I am trying to convert pmsg from a const std::shared_ptr<Message>& to a std::shared_ptr<Message>&.

To get it to work again, I have to introduce a const_cast<std::shared_ptr<Message>&> in the call to the handler.

Where is the const-ness introduced?

Thanks


Solution

  • psmg is captured by value, so it is read only inside closure. If you need it to be modifiable (because that is required by handler) you have to add mutable to the lambda:

    [pmsg](auto err, auto nbytes) mutable { handler(pmsg, err, nbytes); });
    

    Live demo based on BoostAsio


    When pmsg is capture by value, the compiler is allowed to make one implicit conversion, so from pmsg is created temporary shared_ptr instance and passed to handler, but temporary object cannot be bound to Lvalue reference (it could be work with const lvalue ref).