为什么 make_optional 不适用于文件流?

Why doesn't make_optional work for file streams?

我正在试用 C++17 可选类型,并认为使用它的合适位置是尝试打开文件的函数,可能returns打开的文件。我写的函数是这样的:

std::optional<std::fstream> openFile(std::string path)
{
    std::fstream file;
    file.open(path);
    if (!file.is_open())
    {
        std::cerr << "couldn't open file" << path << std::endl;
        return {};
    }
    else
    {
        return std::make_optional(file); // results in compilation error
    }
}

但是,当我尝试使用 g++ 编译它并以 -std=c++17 作为参数之一时,我收到一大堆模板编译错误消息,从以下内容开始:

In file included from read_file.cpp:3:0:
/usr/include/c++/7/optional: In instantiation of ‘constexpr std::optional<typename std::decay<_Tp>::type> std::make_optional(_Tp&&) [with _Tp = std::basic_fstream<char>&; typename std::decay<_Tp>::type = std::basic_fstream<char>]’:
read_file.cpp:16:39:   required from here
/usr/include/c++/7/optional:991:62: error: no matching function for call to ‘std::optional<std::basic_fstream<char> >::optional(<brace-enclosed initializer list>)’
     { return optional<decay_t<_Tp>> { std::forward<_Tp>(__t) }; }

为什么 fstream 似乎不能与 std::optional 一起使用?我是以错误的方式接近这个吗?如果 optional 不支持 stream-types,那不是限制了 type 可以应用的地方吗?

当您将流传递给 make_optional 时,您的代码将尝试复制流。流无法复制,因此需要移动它,即

return std::make_optional(std::move(file));

或者干脆

return file;

(根据编译器的年龄,后者可能不起作用。)

std::make_optional

的形式调用可选的构造函数
template < class U = value_type >
constexpr optional( U&& value );

并且该构造函数的行为与

相同
T optional_data = std::forward<U>(value)

因为你传递了一个左值,所以它会制作一个副本。流是不可复制的,所以你会得到一个错误。您必须 move 流进入可选的才能使其正常工作。