C++ 将 istream in 条件运算符传递给函数
C++ passing istream the in conditional operator to the function
我对条件运算符的行为很困惑。假设这样的函数
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);
error C2248: 'std::basic_istream<char,std::char_traits<char>>::basic_istream': cannot access protected member declared in class '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());
这可以编译,但如果流是使用文件名设置的 ifstream,则在尝试 std::getline(stream, str);
时会在 运行 时间内崩溃。
I've heard something about streams being not-copyable, but I am not copying anything, am I?
是的,不幸的是,你是。
在任何引用绑定发生之前执行从 std::ifstream
到 std::istream
的转换:
[C++11: 5.16/3]:
[..] If E2
is an rvalue or if neither of the conversions above can be done and at least one of the operands has (possibly cv-qualified) class type:
- if
E1
and E2
have class type, and the underlying class types are the same or one is a base class of the other: E1
can be converted to match E2
if the class of T2 is the same type as, or a base class of, the class of T1
, and the cv-qualification of T2
is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification of T1
. If the conversion is applied, E1
is changed to a prvalue of type T2 by copy-initializing a temporary of type T2
from E1
and using that temporary as the converted operand.
[..]
有所有标准方法可以缓解这种情况(您已经探索过其中一些方法)。一个非常讨厌的工作是向 read_from_stream
添加一个重载,它接受一个右值引用,并将两个表达式操作数转换为相同的类型:
#include <fstream>
#include <iostream>
void f(std::istream&&);
int main()
{
f(
false
? (std::istream&&) std::ifstream("/tmp")
: (std::istream&&) std::cin
);
}
(see it compiling)
与我的原始代码测试版相比:
#include <fstream>
#include <iostream>
void f(std::istream&);
int main()
{
f(
false
? std::ifstream("/tmp")
: std::cin
);
}
我对条件运算符的行为很困惑。假设这样的函数
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);
error C2248: 'std::basic_istream<char,std::char_traits<char>>::basic_istream': cannot access protected member declared in class '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());
这可以编译,但如果流是使用文件名设置的 ifstream,则在尝试 std::getline(stream, str);
时会在 运行 时间内崩溃。
I've heard something about streams being not-copyable, but I am not copying anything, am I?
是的,不幸的是,你是。
在任何引用绑定发生之前执行从 std::ifstream
到 std::istream
的转换:
[C++11: 5.16/3]:
[..] IfE2
is an rvalue or if neither of the conversions above can be done and at least one of the operands has (possibly cv-qualified) class type:
- if
E1
andE2
have class type, and the underlying class types are the same or one is a base class of the other:E1
can be converted to matchE2
if the class of T2 is the same type as, or a base class of, the class ofT1
, and the cv-qualification ofT2
is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification ofT1
. If the conversion is applied,E1
is changed to a prvalue of type T2 by copy-initializing a temporary of typeT2
fromE1
and using that temporary as the converted operand.[..]
有所有标准方法可以缓解这种情况(您已经探索过其中一些方法)。一个非常讨厌的工作是向 read_from_stream
添加一个重载,它接受一个右值引用,并将两个表达式操作数转换为相同的类型:
#include <fstream>
#include <iostream>
void f(std::istream&&);
int main()
{
f(
false
? (std::istream&&) std::ifstream("/tmp")
: (std::istream&&) std::cin
);
}
(see it compiling)
与我的原始代码测试版相比:
#include <fstream>
#include <iostream>
void f(std::istream&);
int main()
{
f(
false
? std::ifstream("/tmp")
: std::cin
);
}