12

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

T v;
foo(v);

现在,C++0x 出现了——现在有了右值引用,定义为的函数void foo(T&&)将允许我传递一个临时值。这让我想到了我的问题:既然一个接受右值引用的函数既可以接受右值引用(未命名的临时对象)也可以接受左值引用(命名的非常量引用),是否有任何理由在函数参数中再使用左值引用?我们不应该总是使用右值作为函数参数吗?

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

4

2 回答 2

20

“因为采用右值引用的函数既可以采用右值引用(未命名的临时对象)也可以采用左值引用(命名的非常量引用)”

这是一个不正确的说法。在右值参考规范的第一次迭代中,这是正确的,但它不再是并且至少在 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&);

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

希望这能说明问题。

于 2010-12-23T18:53:22.583 回答
0

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

于 2010-12-23T18:46:05.347 回答