万能引用和引用折叠
引用折叠
引用折叠用于处理当类型别名或模板实例化导致“引用的引用”出现时的情况。
一个模板函数,根据定义的形参和传入的实参的类型,我们可以有下面四中组合:
- 函数定义的形参类型是左值引用,传入的实参是左值引用(
&-&) - 函数定义的形参类型是左值引用,传入的实参是右值引用(
&-&&) - 函数定义的形参类型是右值引用,传入的实参是左值引用(
&&-&) - 函数定义的形参类型是右值引用,传入的实参是右值引用(
&&-&&)
template<typename T>
void foo(T& param) {
}
int main() {
int x = 10;
foo(x); // param推导为:T& &
foo(10); // param推导为:T& &&
}
/************************************/
template<typename T>
void foo(T&& param) {
}
int main() {
int x = 10;
foo(x); // param推导为:T&& &
foo(10); // param推导为:T&& &&
}
C++语法不允许直接声明“引用的引用”,但模板推导可能会间接产生这种形式。为了解决这个问题,C++定义了四条引用折叠规则:
| 组合 | 规则 | 结果 |
|---|---|---|
& - & |
int& & |
int& (左值引用) |
& - && |
int& && |
int& (左值引用) |
&& - & |
int&& & |
int& (左值引用) |
&& - && |
int&& && |
int&& (右值引用) |
简记:
- 只要表达式中出现左值引用(
&),最终结果就是左值引用(&)。 - 只有当表达式中全部都是右值引用(
&&)时,最终结果才是右值引用(&&)。
万能引用
万能引用(Universal Reference)是一种特殊的引用类型,既可以是左值引用,用来绑定左值;也可以是右值引用,用来绑定右值。
它只出现在两种情况下:
- 模板函数的参数:
template<typename T> void func(T&& param); auto推导的变量:auto&& var = expr;
T&&只有在以下两个条件都满足的情况下才是万能引用:
- 必须是函数模板或
auto变量的参数。 T必须是未被任何修饰的(const、volatile等)模板参数,其类型完全由传入的参数推导而来。(const、volatile等修饰会导致退化为普通的右值引用)
区分右值引用和万能引用:万能引用必须涉及模板类型推导(auto本质上也是一种隐式的模板类型推导)
template<typename T>
void foo(T&& param)
{
// param 是万能引用
}
int main
{
int x = 10;
// 传入左值,T被推导为int&
foo(x);
// 传入右值,T被推导为int&&。
foo(20);
}