来自右值的非常量引用的无效初始化
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()
右值被作为非常量引用传递,所以抱怨是合理的,但我能做什么?
- 两个函数参数都不能是
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()
不支持 references/pointers 后面的参数 returns.
例如,不要这样使用:
int& x = lvalue_ref(5);
std::cout << x; // temporary is destructed, therefore Undefined Behavior
只需确保返回引用的生命周期与临时对象的生命周期相对应,就可以了。
所以我有以下功能:
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()
不支持 references/pointers 后面的参数 returns.
例如,不要这样使用:
int& x = lvalue_ref(5);
std::cout << x; // temporary is destructed, therefore Undefined Behavior
只需确保返回引用的生命周期与临时对象的生命周期相对应,就可以了。