C ++ 0x:rvalue引用与非const常量

C ++ 0x:rvalue引用与非const常量

问题描述:

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

When programming in C++03, we can't pass an unnamed temporary T() to a function void foo(T&);. The usual solution is to give the temporary a name, and then pass it like:

T v;
foo(v);

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

Now, along comes C++0x - and now with rvalue references, a function defined as void foo(T&&) will allow me to pass a temporary. Which brings me to my question: since a function that takes an rvalue reference can take both rvalue references (unnamed temporaries) as well as lvalue references (named non-const references), is there any reason to use lvalue references anymore in function parameters? Shouldn't we always use rvalues as function parameters?

授予一个函数,它接受一个左值引用将阻止调用者传递临时,但我不知道这是否是一个有用的限制。

Granted, a function that takes an lvalue reference would prevent the caller from passing a temporary, but I'm not sure if that's a useful restriction.

因为一个函数, rvalue引用(未命名临时)以及lvalue引用(名为非const引用)

"since a function that takes an rvalue reference can take both rvalue references (unnamed temporaries) as well as lvalue references (named non-const references)"

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

This is an incorrect statement. During the first iterations of the rvalue reference specification this was true, but it no longer is and is implemented at least in MSVC to comply with this later change. In other words, this is illegal:

void f(char&&);

char x;
f(x);

为了调用一个期望使用左值的右值引用的函数,必须将它转换为右值:

In order to call a function expecting rvalue references with an lvalue you must turn it into an rvalue like so:

f(std::move(x))

当然,这种语法非常清楚,采用了一个左值引用的函数和一个采用右值引用的函数之间的区别是什么:实际上,右值引用不会存活调用。这是一个大问题。

Of course, that syntax makes it quite clear what the difference between a function taking an lvalue reference and one taking an rvalue reference really is: an rvalue reference is not expected to survive the call. This is a big deal.

现在,你当然可以组成一个新的函数,它完全正确的std :: move,然后你可以使用右值引用类似于左值引用。我想这样做例如一个访问者框架,我有时,你只是不关心访问者调用的任何结果,但其他时候,你做,因此需要一个左值引用在这些情况下。对于右值引用,我可以得到两个...但是这是违反了右值引用语义,我认为这是一个坏主意。

Now, you can of course make up a new function that does exactly what std::move does and then you "can" use rvalue references sort of like lvalue references. I thought about doing this for instance with a visitor framework I have when sometimes you simply don't care about any result of the visitor call, but other times you do and thus need an lvalue reference in those cases. With an rvalue reference I could get both...but it's such a violation of the rvalue reference semantics that I decided it was a bad idea.

您的语句可能是一个基于此的混淆:

Your statement may be a confusion based upon this:

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

char x;
f(x);

这是有效的,但不是因为你传递一个左值作为右值引用。它的工作原因是参考衰减(也是新的在C ++ 0x)。当你传递一个左值到这样的模板,它实际上被实例化如下:

This works, but not because you are passing an lvalue as an rvalue reference. It works because of reference decay (also new in C++0x). When you pass an lvalue to such a template it actually gets instantiated like so:

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

参考衰减表示&&& 变成& ,因此实际的实例化如下所示:

Reference decay says that &&& turns into & so then the actual instantiation looks like this:

void f<char&>(char&);

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

In other words, you're simply passing an lvalue by reference...nothing new or special about that.

希望清除事物。