所以我有以下功能:
void scan(std::istream& is, Handler& h);
我想用不同的方式调用它,比如:
scan(std::cin, Handler());
scan(std::ifstream("myfile"), myhandler);
编译器提示 std::ifstream("myfile")
和 Handler()
是作为非常量引用传递的右值,所以提示是合法的, 但我能做什么呢?
- 两个函数参数都不能是
const
(istream
在读取时被修改并且处理程序在回调期间更改其状态)。 - 如果我将参数类型更改为右值引用 (
&&
) 那么我将无法通过std::cin
并且有时我真的很关心最终状态myhandler
因此我不能对它们应用std::move
。 - 原则上,我可以通过模板或
auto&&
类型推导将参数作为通用引用,从而为左值和右值引用的所有可能组合重载此函数,但我无意重载此函数对于我已经指定的其他类型。
还有其他选择吗?
在这样一个微不足道的例子中,整个移动语义不知何故受到了阻碍。
最佳答案
要将右值转换为左值,您可以使用这个左值辅助函数:
template<class T>
T& lvalue_ref(T&& x) { return x; }
然后调用变成:
scan(lvalue_ref(std::ifstream("myfile")), lvalue_ref(Handler()));
这是安全的,因为临时对象(ifstream
和 Handler
)在完整表达式结束之前不会被破坏。但是,请注意,这些是对临时对象的左值引用,因此在决定使用此方法时必须谨慎。我假设 scan()
在返回后不保存对参数的引用/指针。
例如,不要这样使用:
int& x = lvalue_ref(5);
std::cout << x; // temporary is destructed, therefore Undefined Behavior
只需确保返回引用的生命周期与临时引用的生命周期相对应,就可以了。
关于c++ - 来自右值的非常量引用的无效初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35439619/