The compiler wants my lvalue to be a rvalue reference and I dont see why.
My questions are:
- Why is "dataLen" const, even though it was declared non const and the lambda is told to catch by reference as default?
- 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)
dataLen
is treated as const because you capture it by value: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.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:i
is named object, so it is lvalue. Bymake_tuple<int>
you makemake_tuple
signature look like:make_tuple(int&&)
. This is the place where compiler complains, becausei
as lvalue cannot be bound to rvalue reference. With argument deduction, parameter ofmake_tuple
is deduced to be:int&
, and in this casei
can be bound.push_back
onvector
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.