1.万能引用
1.1 右值引用
右值引用只能绑定到右值上,不能绑定到左值上。
#include <iostream>
using namespace std;
void myfunc(int&& val) // 右值引用
{
cout << val << endl;
return;
}
int main()
{
myfunc(120); // ok
int i = 180;
myfunc(i); // error
return 0;
}
1.2 万能引用
万能引用(universal reference),也称为未定义引用,如果一个变量或参数被声明为 T&&
,并且需要推导 T
的类型,那么该变量或参数即为万能引用。
万能引用,既可以是左值引用,用来绑定左值;也可以是右值引用,用来绑定右值。
应用场景:
- 函数模板自动类型推导
- auto自动类型推导
#include <iostream>
using namespace std;
template <typename T> // 函数模板
void myfunc(T&& val) // 万能引用
{
cout << val << endl;
return;
}
int main()
{
myfunc(120); // ok,自动类型推导,120是右值,T为int类型,val为int&&类型
int i = 180;
myfunc(i); // ok,自动类型推导,i是左值,T为int&类型,val为int&类型
return 0;
}
1.3 注意区分万能引用和右值引用
#include <iostream>
using namespace std;
template <typename T> // 类模板
class myclass
{
public:
void myfunc1(T&& x) // 右值引用
{
cout << x << endl;
return;
}
template <typename U>
void myfunc2(U&& val) // 万能引用
{
cout << val << endl;
return;
}
};
int main()
{
int i = 180;
myclass<int> mc;
mc.myfunc1(120); // ok
mc.myfunc1(i); // error
mc.myfunc2(120); // ok
mc.myfunc2(i); // ok
return 0;
}
1.4 const会剥夺万能引用的资格
#include <iostream>
using namespace std;
template <typename T> // 函数模板
void myfunc(const T&& val) // 右值引用
{
cout << val << endl;
return;
}
int main()
{
myfunc(120); // ok
int i = 180;
myfunc(i); // error
return 0;
}
2.引用折叠
为什么万能引用既可以是左值引用,也可以是右值引用呢?这就涉及到 C++ 的引用折叠语法了。
引用分为左值引用 T&
和右值引用 T&&
两种,那么将这两种引用进行排列组合,就会有四种情况。
所有的引用折叠最终都代表一个引用,要么是左值引用,要么是右值引用。
规则就是:如果任一引用为左值引用,则结果为左值引用;否则,结果为右值引用。
引用折叠前 | 引用折叠后 | |
---|---|---|
左值引用-左值引用 | T& & | T& |
左值引用-右值引用 | T& && | T& |
右值引用-左值引用 | T&& & | T& |
右值引用-右值引用 | T&& && | T&& |
需要注意的是,不存在“引用的引用”,编译器不允许我们显式写出类似 int& &&
这样的代码。