The compiler wants my lvalue to be a rvalue reference and I dont see why.
My questions are:
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:
[&, 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.
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.