0

0

C++中的forwarding reference万能引用是什么?(T&&在模板推导中的引用折叠)

穿越時空

穿越時空

发布时间:2026-01-13 13:09:11

|

156人浏览过

|

来源于php中文网

原创

forwarding reference(万能引用)是模板参数T&&在T为未限定模板参数时的特殊行为,可绑定左值或右值;其本质依赖引用折叠规则:T& &&→T&,T&& &&→T&&;必须配合std::forward在模板函数内使用以完美转发。

c++中的forwarding reference万能引用是什么?(t&&在模板推导中的引用折叠)

什么是forwarding reference(万能引用)?

它不是一种新类型,而是 T&& 在特定模板上下文中的一种特殊行为:当 T 是模板参数且未被显式指定为某个具体类型时,T&& 可能绑定左值或右值,从而实现“既能转发左值又能转发右值”的能力。

关键前提是:必须是「未加限定的模板参数」+ 「&&」。比如:

template
void f(T&& x); // ✅ forwarding reference

而这些都不是:

template
void f(const T&& x); // ❌ 右值引用(非万能)
void g(int&& x);      // ❌ 普通右值引用
template
void h(std::vector&& x); // ❌ 绑定到具体类型,不是T&&

引用折叠规则怎么影响推导结果?

万能引用之所以能“万能”,靠的是 C++11 引入的引用折叠规则(reference collapsing),它在模板实参推导后起作用。核心只有两条:

立即学习C++免费学习笔记(深入)”;

  • T& & → T&
  • T&& & → T&
  • T& && → T&
  • T&& && → T&&

实际推导过程分两步:

① 根据实参类型推导 T(注意:左值会推成 T&,右值推成 T);

② 对 T&& 应用引用折叠。

例如:

Rationale
Rationale

Rationale 是一款可帮助企业主、经理和个人做出艰难的决定的AI工具

下载
template
void f(T&& x) {}

int i = 42; f(i); // i是左值 → T 推导为 int& → T&& 变成 int& && → 折叠为 int& f(42); // 42是右值 → T 推导为 int → T&& 就是 int&&

为什么std::forward(x)必须配合万能引用使用?

std::forward 本身不改变值类别,它只是根据你传入的模板实参 T 决定返回左值引用还是右值引用。它的作用是“恢复”原始实参的值类别,但前提是:你得先通过万能引用捕获了这个信息。

常见错误是直接对普通变量用 std::forward

int x = 42;
auto&& y = x;           // y 是 int&
std::forward(y);   // ❌ 强制转成 int&&,但 y 本来是左值,语义错
std::forward(y); // ✅ decltype(y) 是 int& → forward(y) → int&

正确用法只出现在万能引用函数体内:

template
void wrapper(T&& x) {
    some_func(std::forward(x)); // ✅ 保留x原本是左值/右值的性质
}

容易踩的坑:什么时候T&&不是万能引用?

最常误判的情况是「带 cv 限定或嵌套类型的 T&&」——只要 T 不是裸模板参数,就退化为普通右值引用:

  • template void f(const T&& x) → 只接受右值,且禁止绑定 const 左值
  • template void f(T*&& x) → 只接受右值指针,不能绑定 int* p; 这样的左值指针
  • template void f(std::unique_ptr&& x) → 普通右值引用,和万能无关

另一个隐蔽问题是:函数重载中万能引用可能产生意外匹配优先级。比如:

void f(int&);           // 左值重载
void f(int&&);          // 右值重载
template void f(T&&); // 万能引用(非 const)

f(42); // 调用 f(int&&),不是模板 int i = 42; f(i); // 调用 f(int&),不是模板 —— 因为非模板更匹配

但如果把前两个删掉,仅留模板版本,它就会接管所有调用——此时是否符合预期,得看设计意图。

真正难处理的点在于:引用折叠是编译期隐式发生的,不报错也不提示;你看到 T&& 就默认它是万能的,但一旦加了 const 或换了个类型,行为就彻底变了。写模板时务必确认 T 是原样出现的。

相关专题

更多
c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

521

2023.09.20

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

536

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

52

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

194

2025.08.29

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

175

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

97

2025.11.27

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

1

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

5

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 45.4万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号