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

时间:2015-03-31 14:44:39

标签: c++ stream ternary-operator

我对条件运算符的行为很困惑。假设这样的功能

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 :(

好的,将SomeData从if-else

中删除
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_istream< char,std :: char_traits< char>> :: basic_istream':无法访问在类'std :: basic_istream< char,std :: char_traits< char>中声明的受保护成员>'

好吧,我听说过一些关于溪流不可复制的东西,但我不是在复制任何东西,是吗?

修改

我想出了这个

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());

这会编译,但如果使用filename设置了ifstream流,那么在尝试std::getline(stream, str);时,它会在运行时崩溃。

1 个答案:

答案 0 :(得分:1)

  

我听说过一些关于溪流不可复制的内容,但我没有复制任何内容,是吗?

是的,不幸的是,你是。

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

  

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

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

[..]

有减轻这种情况的所有标准方法(其中一些已经探讨过)。一个非常讨厌的工作方法是向E1添加一个带有右值引用的重载,并将两个表达式操作数转换为相同的类型:

read_from_stream

see it compiling

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

#include <fstream>
#include <iostream>

void f(std::istream&&);

int main()
{
    f(
        false
        ? (std::istream&&) std::ifstream("/tmp")
        : (std::istream&&) std::cin
    );
}

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