C2664 cannot convert to && value

1.3k Views Asked by At

The compiler wants my lvalue to be a rvalue reference and I dont see why.

My questions are:

  1. Why is "dataLen" const, even though it was declared non const and the lambda is told to catch by reference as default?
  2. Why does the compiler try to convert to rvalue reference "unsigned __int64 &&", even though it was declared "unsigned long long" (no rvalue reference) for tupleByteVector_content?

I think it is because of the lambda capture, but please see this simplified workflow below:

void read_socket()
{
  std::vector<std::tuple<unsigned long long, std::vector<unsigned char>>> tupleByteVector_content;
  read_socket_readSome(tupleByteVector_content, [this, &tupleByteVector_content]() {
    //use tuple vector
  });
}

//catch the tuple vector by reference
void read_socket_readSome(std::vector<std::tuple<unsigned long long, const std::shared_ptr<Session>& session, std::vector<unsigned char>>> & tupleByteVector_content, std::function<void()> && continueReadFunction)
{
  //Read data length from a asio socket
  std::shared_ptr<asio::streambuf> len_buffer = std::make_shared<asio::streambuf>();
  asio::async_read(session->connection->socket->next_layer(), *len_buffer, asio::transfer_exactly(1), [&, 
  this, session, len_buffer, tupleByteVector_content, continueReadFunction](const error_code& ec, std::size_t bytes_transferred) {

    //the first value I want to save
    unsigned long long dataLen = BytesToLength(len_buffer);

    //Read data from a asio socket
    std::shared_ptr<asio::streambuf> data_buffer = std::make_shared<asio::streambuf>();
    asio::async_read(session->connection->socket->next_layer(), *data_buffer, asio::transfer_exactly(dataLen), [&, this, dataLen, data_buffer, tupleByteVector_content, session, continueReadFunction](const error_code& ec, std::size_t bytes_transferred) {

        //ERROR HERE: ----------->

        std::tuple<unsigned long long, std::vector<unsigned char>> t = 
          std::make_tuple<unsigned long long, std::vector<unsigned char>>(

          dataLen, // ERROR C2664, cant convert argument 1 from "const unsigned __int64" to "unsigned __int64 &&"

          { asio::buffers_begin(data_buffer->data()), asio::buffers_end(data_buffer->data()) });

        //ERROR HERE: <-----------
        
        tupleByteVector_content.push_back(t);

        continueReadFunction();

    });
  });
}

EDIT: I was able to compile this tuple:

std::tuple<unsigned long long, std::vector<unsigned char>> t = { dataLen, { asio::buffers_begin(data_buffer->data()), asio::buffers_end(data_buffer->data()) } };

But then the push_back to the vector gives the error: error C2663: [...] ::push_back": for 2 overloads there is no conversion for the this-pointer (free translation into english from myself)

1

There are 1 best solutions below

3
On BEST ANSWER
  1. dataLen is treated as const because you capture it by value:

    [&, this, dataLen,
              ^^^
    

By default function call operator generated for closure is marked as const, so inside const method you can only read data. Modifications are not allowed, unless you add mutable to definition of lambda.

  1. When you use make_tuple you should rely on template argument deduction instead putting types in explicit way, as you did it. Short version of your issue:

     int i;
     std::tuple<int> t = std::make_tuple<int>(i);
    

i is named object, so it is lvalue. By make_tuple<int> you make make_tuple signature look like: make_tuple(int&&). This is the place where compiler complains, because i as lvalue cannot be bound to rvalue reference. With argument deduction, parameter of make_tuple is deduced to be: int&, and in this case i can be bound.

push_back on vector doesn't work, because again you captured vector by value. push_back modifies object, which is not allowed when calling on const object. You should capture it by reference.