C++的右值引用的几个坑
文章目录
- 有名字的一定是左值;能取地址的一定是左值。这一点最坑:
int && a = 1;
请问a是左值还是右值?a有名字,因此a是左值,a是一个右值引用,a和1 绑定。
|
|
a是一个右值引用,指向一个临时对象,那么a是右值么?不是,是左值,而且可以对a取地址。
std::cout << &a << std::endl;
- T&& 有时候是右值引用类型,有时候是universal reference
什么意思?因为C++给T&&开了特例,允许给T&&传入一个左值,并根据折叠规则(T&& & = T& T&& && = T&&)进行类型推断。因此T&&是万能的reference,即universal reference。对universal reference有一个判断标准:
If a variable or parameter is declared to have type T&& for some deduced type T, that variable or parameter is a universal reference.
什么意思?如果一个变量或者函数的形参T&&需要类型推导,那么他一定是universal reference。举个栗子:
|
|
这个t是universal reference,因为他什么都接,可以是左值,也可以是右值,但是根据上一条规则,t本身是一个左值!
但是我们把他模板特化:
fuck<int>();
此时T=int,模板为: void fuck(int && t)
该函数只能接收右值。也就是说移动构造函数是对的,因为移动构造函数长这个样子:
|
|
此时类型是固定的,不需要推导,因此只能接收右值。t是一个右值引用,而且t是左值。
OK,有了以上这些规则之后来看这个诡异的代码:
- 诡异的重载
|
|
请问这两个函数调用会输出哪个结果?答案都是lvalue。根据第一条规则,有名字的都是左值,在superfuck内f是一个左值,类型为T&,导致fuck函数只能接收左值。有的人说T&& f是universal reference啥都能收,也是candidate,此处是为了精确匹配。
那如果将引用改一个会如何?把第一个重载模板改成const T &f,会怎样?
|
|
答案是输出全部变成了右值!为啥?因为模板匹配的时候优先考虑没有const的candidate,此时universal reference版本变成了较好的版本。参见overload reference。本身传入的是一个非const的左值,这样通过模板推导出来的fuck(T &f)更精确一些,因此会选择输出右值的函数。
|
|
是不是很崩溃?
文章作者 xnhp0320
上次更新 2017-04-03