来自右值的非常量引用的无效初始化

invalid initialization of non-const reference from an rvalue

所以我有以下功能:

void scan(std::istream& is, Handler& h);

我想用不同的方式调用它,例如:

scan(std::cin, Handler());
scan(std::ifstream("myfile"), myhandler);

编译器抱怨 std::ifstream("myfile")Handler() 右值被作为非常量引用传递,所以抱怨是合理的,但我能做什么?

  1. 两个函数参数都不能是 constistream 在读取时被修改并且处理程序在回调期间更改其状态)。
  2. 如果我将参数类型更改为右值引用 (&&) 那么我将无法传递 std::cin 并且有时我真的很关心 myhandler 的最终状态因此我也不能对它们应用 std::move
  3. 原则上,我可以通过模板或 auto&& 类型推导将参数作为通用引用,从而为左值和右值引用的所有可能组合重载此函数,但我无意为以下重载此函数我已经指定的其他类型。

还有其他选择吗?

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

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

template<class T>
T& lvalue_ref(T&& x) { return x; }

然后调用变为:

scan(lvalue_ref(std::ifstream("myfile")), lvalue_ref(Handler()));

这是安全的,因为临时变量(ifstreamHandler)在完整表达式结束之前不会被破坏。但是,请注意,这些是对临时对象的左值引用,因此在决定使用此方法时必须谨慎。我假设 scan() 不支持 references/pointers 后面的参数 returns.

例如,不要这样使用:

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

只需确保返回引用的生命周期与临时对象的生命周期相对应,就可以了。