“因为采用右值引用的函数既可以采用右值引用(未命名的临时对象)也可以采用左值引用(命名的非常量引用)”
这是一个不正确的说法。在右值参考规范的第一次迭代中,这是正确的,但它不再是并且至少在 MSVC 中实现以符合后来的变化。换句话说,这是非法的:
void f(char&&);
char x;
f(x);
为了使用左值调用期望右值引用的函数,您必须将其转换为右值,如下所示:
f(std::move(x))
当然,该语法清楚地表明了一个函数采用左值引用和一个采用右值引用的函数之间的真正区别是:右值引用不会在调用中存活下来。这是一个大问题。
现在,您当然可以创建一个新函数来完全执行 std::move 所做的事情,然后您“可以”使用类似于左值引用的右值引用。例如,我考虑过使用访问者框架执行此操作,有时您根本不关心访问者调用的任何结果,但有时您会这样做,因此在这些情况下需要左值引用。使用右值引用,我可以同时获得两者……但它违反了右值引用语义,我认为这是一个坏主意。
基于此,您的陈述可能会造成混淆:
template < typename T >
void f(T&&);
char x;
f(x);
这有效,但不是因为您将左值作为右值引用传递。它的工作原理是参考衰减(C++0x 中也是新的)。当您将左值传递给这样的模板时,它实际上会像这样被实例化:
void f<char&>(char&&&);
参考衰减说&&&
变成了&
这样,那么实际的实例化看起来像这样:
void f<char&>(char&);
换句话说,您只是通过引用传递一个左值......这没有什么新的或特别的。
希望这能说明问题。