C ++ 0x:rvalue引用与非const lvalue

时间:2010-12-23 18:43:09

标签: c++ c++11 lvalue rvalue-reference

在C ++ 03中编程时,我们无法将未命名的临时T()传递给函数void foo(T&);。通常的解决方案是给临时名称,然后传递它:

T v;
foo(v);

现在,沿着C ++ 0x - 现在有了rvalue引用,定义为void foo(T&&)的函数将允许我传递一个临时值。这让我想到了一个问题:因为一个采用右值引用的函数可以同时使用右值引用(未命名的临时值)以及左值引用(命名为非const引用),是否有理由在函数参数中再使用左值引用?我们不应该总是使用rvalues作为函数参数吗?

当然,一个采用左值引用的函数会阻止调用者传递临时值,但我不确定这是否是一个有用的限制。

2 个答案:

答案 0 :(得分:19)

“因为采用右值引用的函数可以同时使用右值引用(未命名的临时值)以及左值引用(命名为非const引用)”

这是一个不正确的陈述。在右值参考规范的第一次迭代期间,这是真的,但它不再是并且至少在MSVC中实现以符合后来的更改。换句话说,这是非法的:

void f(char&&);

char x;
f(x);

为了调用一个期望带左值的右值引用的函数,你必须把它变成一个像这样的右值:

f(std::move(x))

当然,该语法非常清楚地表明采用左值引用的函数与采用右值引用的函数之间的区别是:rvalue引用不会在调用中存活。这是一个大问题。

现在,您当然可以组成一个新函数,它完全执行std :: move所做的操作,然后您“可以”使用rvalue引用类似于左值引用。我考虑过这样做,例如我有一个访问者框架,有时你根本不关心访问者调用的任何结果,但有时你做,因此在这些情况下需要左值引用。使用rvalue引用我可以得到两个......但是它违反了rvalue引用语义,我认为这是一个坏主意。

基于此,您的陈述可能会引起混淆:

template < typename T >
void f(T&&);

char x;
f(x);

这样可行,但不是因为您将左值作为右值引用传递。它的工作原理是参考衰减(也是C ++ 0x中的新增功能)。当你将左值传递给这样一个模板时,它实际上是这样实例化的:

void f<char&>(char&&&);

引用decay表示&&&变为&,因此实际的实例化如下所示:

void f<char&>(char&);

换句话说,你只是通过引用传递一个左值......没什么新的或特别的。

希望能够解决问题。

答案 1 :(得分:0)

如果必须主动处理临时值,例如指向new内存的指针或文件句柄等有限资源,则这是一个有用的限制。但需要传递这些背后的气味更多的是“糟糕的设计”而不是“有用的限制”。