从右值初始化非const引用无效

mar*_*usm 3 c++ rvalue-reference c++11 type-deduction c++14

所以我有以下功能:

void scan(std::istream& is, Handler& h);
Run Code Online (Sandbox Code Playgroud)

我想以不同的方式称呼它,例如:

scan(std::cin, Handler());
scan(std::ifstream("myfile"), myhandler);
Run Code Online (Sandbox Code Playgroud)

编译器抱怨std::ifstream("myfile")并且Handler()将rvalues作为非const引用传递,因此投诉是合法的,但我该怎么办?

  1. 两个函数参数都不能const(istream读取时修改,处理程序在回调期间更改其状态).
  2. 如果我将参数类型更改为rvalue references(&&),那么我将无法通过std::cin,有时我真的关心最终状态,myhandler因此我也无法应用std::move它们.
  3. 原则上我可以通过模板或auto&&类型推导使参数成为通用引用,从而为lvalue和rvalue引用的所有可能组合重载此函数,但我不打算将此函数重载为我已经指定的其他类型.

还有其他选择吗?

不知何故,整个移动语义在这样一个微不足道的例子中受到了阻碍.

0x4*_*2D2 7

要将右值转换为左值,可以使用此左值辅助函数:

template<class T>
T& lvalue_ref(T&& x) { return x; }
Run Code Online (Sandbox Code Playgroud)

然后电话变成:

scan(lvalue_ref(std::ifstream("myfile")), lvalue_ref(Handler()));
Run Code Online (Sandbox Code Playgroud)

这是安全的,因为临时表(ifstreamHandler)在完整表达结束之前不会被破坏.但请注意,这些是对临时值的左值引用,因此在决定使用此方法时必须谨慎.我假设scan()它返回后不保存参数的引用/指针.

例如,不要像这样使用它:

int& x = lvalue_ref(5);
std::cout << x; // temporary is destructed, therefore Undefined Behavior
Run Code Online (Sandbox Code Playgroud)

只要确保返回的引用的生命周期与临时引用的生命周期相符,你就可以了.