C++0x:rvalue引用与非const左值

13

在C++03中编程时,我们不能将未命名的临时对象T()传递给函数void foo(T&);。通常的解决方案是给临时对象命名,然后像这样传递:

T v;
foo(v);

现在,C++0x推出了右值引用,一个被定义为void foo(T&&)的函数将允许我传递一个临时对象。这就是我的问题所在:既然一个接受右值引用的函数可以同时接受右值引用(未命名的临时对象)和左值引用(命名的非const引用),那么还有什么理由在函数参数中使用左值引用呢?我们不应该总是使用右值作为函数参数吗?
当然,一个接受左值引用的函数可以防止调用者传递一个临时对象,但我不确定这是否是一个有用的限制。

2
如果例程尝试将参数的地址存储在某个地方以供将来使用,那将是一个非常有用的限制。 - T.E.D.
2个回答

21
“由于接受右值引用的函数可以接受右值引用(未命名临时对象)以及左值引用(命名非常量引用)”,这是一个错误的陈述。在rvalue引用规范的前几个版本中,这是正确的,但现在已经不再是了,并且至少在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&);

换句话说,你只是传递一个左值的引用...没有什么新的或特别的地方。
希望这能澄清问题。

0

如果需要主动处理临时变量,例如指向new内存或类似文件句柄的有限资源,则这是一个有用的限制。但是,需要将它们传递回去更像是“糟糕的设计”,而不是“有用的限制”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接