【问题标题】:invalid initialization of non-const reference from an rvalue来自右值的非常量引用的无效初始化
【发布时间】:2016-02-16 17:49:17
【问题描述】:

所以我有以下功能:

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&& 类型推导将参数作为通用引用,从而为左值和右值引用的所有可能组合重载此函数,但我无意为除我之外的其他类型重载此函数已经指定了。

还有其他选择吗?

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

【问题讨论】:

  • std::ifstream("myfile") 是一个临时值,为什么不简单地为它创建一个变量呢?
  • 这与移动语义无关。
  • template<class T>T& lvalue_ref(T&& x){return x;} 然后稍后 - scan(lvalue_ref(ifstream()), lvalue_ref(Handler()))
  • @mariusm 这是使用指针而不是引用的正当理由。您还可以在 switch/case 块中创建变量,将它们放入范围块 ({})。
  • 你为什么不constrain一个函数模板?

标签: c++ c++11 c++14 rvalue-reference type-deduction


【解决方案1】:

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

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

然后调用变成:

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

这是安全的,因为临时变量(ifstreamHandler)在完整表达式结束之前不会被破坏。但是,请注意,这些是对临时对象的左值引用,因此在决定使用此方法时必须小心。我假设 scan() 在返回后不包含指向参数的引用/指针。

例如,不要这样使用:

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

只要确保返回引用的生命周期与临时引用的生命周期一致,就可以了。

【讨论】:

  • 非常好,也解释了为什么一般不鼓励这样做。谢谢!
猜你喜欢
  • 1970-01-01
  • 2020-05-15
  • 1970-01-01
  • 1970-01-01
  • 2015-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多