返回不可复制对象的元组

Dar*_*ter 10 c++

考虑以下:

#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");
}
Run Code Online (Sandbox Code Playgroud)

由于无法复制file,因此无法编译。

return std::make_tuple(std::move(file), data);可以,但是我问自己“这是否意味着它正在复制而不是data现在移动?”,所以我宁愿有一个通用的解决方案。

但是两者都没有(至少在这里期望移动语义/复制省略):

const auto check_and_read = [](const auto & filename)
-> std::tuple<std::ifstream, std::vector<std::byte>> {

…

return {file, data}
Run Code Online (Sandbox Code Playgroud)

也(不是应该从右值引用的元组构造出此举动吗?)

const auto check_and_read = [](const auto & filename)
-> std::tuple<std::ifstream, std::vector<std::byte>> {

…

return std::forward_as_tuple(file, data);
Run Code Online (Sandbox Code Playgroud)

似乎有效。

是否有某种标准的方法来确保在返回多个参数时无需std::move分别每个参数就可以进行移动构造?

Fra*_*ank 8

考虑以下:

std::tuple<std::string, std::string> foo() {
  std::string a = "hello";

  return {a, a};
}
Run Code Online (Sandbox Code Playgroud)

在特定表达式中使用filedata隐式安全地移动的事实并不意味着即使在非常相似的表达式中也总是如此。

编译器必须确定命名标识符注定要失败,才能将其视为r值,这样的分析很快就会变得不合理地复杂。


jca*_*cai 7

没有标准功能,但是应该可以使用(C ++ 17):

template <class... Types>
auto move_to_tuple(Types&&... args) {
    return std::make_tuple(std::move(args)...);
}
Run Code Online (Sandbox Code Playgroud)