我对条件运算符的行为很困惑。假设这样的功能
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);
时,它会在运行时崩溃。
答案 0 :(得分:1)
我听说过一些关于溪流不可复制的内容,但我没有复制任何内容,是吗?
是的,不幸的是,你是。
在发生任何引用绑定之前,从std::ifstream
到std::istream
执行转换:
[C++11: 5.16/3]:
[..] 如果E2
是左值,或者上述任何转化都无法完成并且至少有一个操作数具有(可能是cv限定的)类类型:
- 如果
E1
和E2
具有类类型,基础类类型相同或其中一个是另一个类的基类:{{1如果T2的类与E1
的类的基类相同,则可以转换为匹配E2
T1
的cv资格是与T2
的cv资格相同的cv资格或更高的cv资格。 如果应用了转换,则T1
通过从E1
复制初始化T2
类型的临时值并将该临时值用作转换后的操作数,将更改为类型为T2的prvalue。 强>[..]
有减轻这种情况的所有标准方法(其中一些已经探讨过)。一个非常讨厌的工作方法是向E1
添加一个带有右值引用的重载,并将两个表达式操作数转换为相同的类型:
read_from_stream
与原始代码的测试版本相比:
#include <fstream>
#include <iostream>
void f(std::istream&&);
int main()
{
f(
false
? (std::istream&&) std::ifstream("/tmp")
: (std::istream&&) std::cin
);
}