C++将条件运算符中的istream传递给函数

C++ passing istream the in conditional operator to the function

本文关键字:函数 istream 条件运算符 C++      更新时间:2023-10-16

我对条件运算符的行为很困惑。假设函数类似于

SomeData read_from_stream(istream& stream);

函数本身正在返回一些我们想要捕获的数据包。

if (file_name != "")
    SomeData data = read_from_stream(ifstream(file_name)); // calling cpy/move constructor
else
    SomeData data = read_from_stream(cin);
// data out of scope :(

好的,然后从if-else 中取出SomeData

SomeData data; // calling default constructor :(
if (file_name != "")
    data = read_from_stream(ifstream(file_name));
else
    data = read_from_stream(cin);

默认构造函数甚至可能不存在。好吧,那就另辟蹊径吧。

SomeData data = read_from_stream((file_name != "") ? ifstream(file_name) : cin);

错误C2248:"std::basic_stream<char,std::char_traits<char>>::basic_stream":无法访问类"std::basic_istream<中声明的受保护成员;char,std::char_traits<字符>>'

嗯,我听说流是不可复制的,但我没有复制任何东西,是吗?

编辑:

我想出了这个

auto lmbd = [&file_name]() -> istream& {
    if (file_name != "")
        return ifstream(file_name); // returning reference to temporary :(
    else
        return cin;
};
SomeData data = read_from_stream(lmbd());

这会编译,但如果流是使用文件名设置的ifstream,则在运行时尝试std::getline(stream, str);时会崩溃。

我听说流是不可复制的,但我没有复制任何东西,是吗?

是的,不幸的是,你是。

在发生任何引用绑定之前,执行从std::ifstreamstd::istream的转换:

[C++11: 5.16/3]:[..]如果E2是右值,或者如果上面的转换都不能完成,并且至少有一个操作数具有(可能是cv限定的)类类型:

  • 如果E1E2具有类类型,并且底层类类型相同,或者其中一个是另一个的基类:如果T2的类与T1的类类型相同,或其基类,则E1可以转换为匹配E2,并且T2的cv资格与,或者比T1的cv资格更大的cv资质如果应用转换,则通过从E1复制初始化T2类型的临时值并将该临时值用作转换后的操作数,将E1更改为T2类型的prvalue

[..]

有所有的标准方法可以缓解这种情况(其中一些你已经探索过了)。一个真正令人讨厌的方法是向read_from_stream添加一个重载,该重载接受右值引用,并将两个表达式操作数强制转换为同一类型:

#include <fstream>
#include <iostream>
void f(std::istream&&);
int main()
{
    f(
        false
        ? (std::istream&&) std::ifstream("/tmp")
        : (std::istream&&) std::cin
    );
}

(见编译)

与我的原始代码的测试版本相比:

#include <fstream>
#include <iostream>
void f(std::istream&);
int main()
{
    f(
        false
        ? std::ifstream("/tmp")
        : std::cin
    );
}

("error: use of deleted function 'std::basic_istream<char>::basic_istream(const std::basic_istream<char>&)'")