C++进阶:1. 引用折叠规则
C++ 引用折叠规则
引用折叠(Reference Collapsing)是 C++ 模板和auto类型推导中的核心隐式规则,专门解决多层引用嵌套(如T& &、T&& &)的问题——C++ 语法不允许直接写“引用的引用”,编译器会通过引用折叠将多层引用化简为单层引用。
一、核心规则
只有2 条铁律,所有嵌套引用最终都会被折叠成:
- 只要任意一层是左值引用(&),最终结果就是左值引用(&)
- 只有两层都是右值引用(&&),最终结果才是右值引用(&&)
简化表格:
| 嵌套写法 | 折叠结果 | 口诀 |
|---|---|---|
T& & | T& | 有左则左 |
T& && | T& | 有左则左 |
T&& & | T& | 有左则左 |
T&& && | T&& | 双右才右 |
注意:这是编译器自动执行的规则,你不能手动写
T& &,但模板/auto推导时会自动生成。
二、规则的诞生背景
C++11 引入右值引用后,模板/auto推导会产生引用嵌套,例如:
template<typenameT>voidfunc(T&¶m){}// 万能引用(Forwarding Reference)当你传入左值/右值时,编译器会推导出嵌套引用,再触发折叠:
intx=10;func(x);// x 是左值 → T 推导为 int& → T&& = int& && → 折叠为 int&func(10);// 10 是右值 → T 推导为 int → T&& = int&& → 无折叠,保持 int&&三、最常见场景:万能引用 + 引用折叠
万能引用(T&&/auto&&)的核心就是引用折叠,它能完美保留参数的左/右值属性:
1. 模板中的万能引用
template<typenameT>voidforward(T&&val){// T&& 是万能引用,推导后触发引用折叠}inta=5;forward(a);// 传入左值 int → T = int&// 类型:int& && → 折叠为 int&(左值引用)forward(10);// 传入右值 int → T = int// 类型:int&&(无折叠,右值引用)2. auto 中的万能引用
auto&&x=a;// a 是左值 → auto 推导为 int&// 类型:int& && → 折叠为 int&auto&&y=10;// 10 是右值 → auto 推导为 int// 类型:int&&四、完整推导示例
我们直接看编译器的推导+折叠全过程:
// 模板函数template<typenameT>voidtest(T&&arg){}// 测试1:传入左值 intintnum=20;test(num);// 推导步骤:// 1. T 推导为 int&// 2. T&& = int& &&// 3. 引用折叠 → int&// 测试2:传入右值 inttest(20);// 推导步骤:// 1. T 推导为 int// 2. T&& = int&&// 3. 无折叠 → int&&五、关键作用:完美转发(std::forward)
引用折叠是std::forward(完美转发)的底层原理:
- 它利用引用折叠规则,100% 保留参数的左值/右值属性
- 让函数参数在传递过程中不丢失值类型,避免不必要的拷贝
示例:
#include<utility>template<typenameT,typename...Args>Tcreate(Args&&...args){// 完美转发:保留 args 的左/右值属性,靠引用折叠实现returnT(std::forward<Args>(args)...);}六、总结(必背)
- 规则:有左则左,双右才右
- 触发场景:模板
T&&、auto&&(万能引用)的类型推导 - 核心目的:解决“引用的引用”语法非法问题,实现完美转发
- 结果:所有嵌套引用最终只会是
&或&&两种之一
总结
- 引用折叠是编译器自动化简嵌套引用的隐式规则;
- 核心口诀:有左则左,双右才右;
- 它是万能引用和**
std::forward完美转发**的底层基础。
