consider the following:
#include <fstream>
#include <tuple>
#include <utility>
#include <vector>
const auto length_of_file = [](auto & file){
file.seekg(0, std::ios::end);
std::streampos length = file.tellg();
file.seekg(0, std::ios::beg);
return length;
};
int main(int, char * []) {
const auto check_and_read = [](const auto & filename){
std::ifstream file(filename, std::ios::binary);
file.exceptions(std::ios::failbit | std::ios::badbit);
std::vector<std::byte> data(length_of_file(file));
file.read(reinterpret_cast<char*>(data.data()), data.size());
return std::make_tuple(file, data);
};
auto [file, data] = check_and_read("foo.txt");
}
This doesn’t compile because it wants to copy file
which isn’t possible.
return std::make_tuple(std::move(file), data);
works, but then i’m asking myself »Does this mean it’s copying instead of moving data
now?«, so i would rather have a generic solution for this.
But neither (expecting move semantics/copy elision to kick in at least here):
const auto check_and_read = [](const auto & filename)
-> std::tuple<std::ifstream, std::vector<std::byte>> {
…
return {file, data}
nor (shouldn’t this move construct from a tuple of rvalue references?)
const auto check_and_read = [](const auto & filename)
-> std::tuple<std::ifstream, std::vector<std::byte>> {
…
return std::forward_as_tuple(file, data);
seems to work.
Is there some standard way to ensure move construction on return of multiple arguments without having to std::move
each one individually?
Consider the following:
std::tuple<std::string, std::string> foo() {
std::string a = "hello";
return {a, a};
}
The fact that your usage of file
and data
in your specific expressions is implicitely safely movable does not mean that it's always the case, even for very similar expressions.
The compiler has to be CERTAIN that the named identifier is doomed in order to treat it as a r-value, and such an analysis would quickly become unreasonably complex.
There's no standard function, but this should work (C++17):
template <class... Types>
auto move_to_tuple(Types&&... args) {
return std::make_tuple(std::move(args)...);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With