当前位置: 首页 > news >正文

C++编程之 万能引用

万能引用是一种可以同时接受左值或右值的引用,它的形式是T&&,其中T是一个模板参数。万能引用不是C++的一个新特性,而是利用了模板类型推导引用折叠的规则来实现的功能。

模板类型推导

模板类型推导是指在调用一个模板函数时,编译器会根据传入的实参来推导出模板参数的类型。例如:

template<class T>
void f(T t) {}int x = 10; // x 是左值
f(x); // 调用f时,T被推导为int(注意而不是int&)
f(20); // 调用f时,T被推导为int

之所以调用f(x)时,T被推导为int,这是因为如果实参是一个左值,那么它会被当作一个右值来处理,除非模板参数的形式是T&或者T&&。例如:

template<class T>
void h(T t) {}template<class T>
void i(T& t) {}template<class T>
void j(T&& t) {}int x = 10; // x 是左值
h(x); // 调用h时,T被推导为int
i(x); // 调用i时,T被推导为int
j(x); // 调用j时,T被推导为int&

你可以看到,在调用h和i时,T都被推导为int,而在调用j时,T才被推导为int&。这是因为在j的模板参数中使用了&&符号,这样就触发了万能引用的机制。

当模板参数的形式为T&的时候:

template<class T>
void k(T& t) {}int x = 10; // x 是左值
k(x); // 调用k时,T被推导为int
k(20); // 调用k时,编译错误,因为不能把右值绑定到非常量左值引用上

你可以看到,在调用k时,如果传入一个右值,就会发生编译错误。这是因为右值是临时的,不能被修改或者延长其生命周期。如果想要让模板函数接受右值,可以使用常量左值引用或者右值引用作为模板参数的形式。

引用折叠

引用折叠是指在定义一个引用类型时,如果它本身就是一个引用类型,那么会发生如下的转换:

  • 左值引用& + 左值引用& = 左值引用&
  • 右值引用&& + 右值引用&& = 右值引用&&
  • 左值引用& + 右值引用&& = 左值引用&
  • 右值引用&& + 左值引用& = 左值引用&

例如:

int x = 10; // x 是左值
int &r1 = x; // r1 是左值引用
int &&r2 = 20; // r2 是右值引用// 引入了两个别名类型:
using LRef = int &;
using RRef = int &&;LRef &r3 = r1; // r3 的类型是 LRef &,即 int & &,经过折叠后变为 int &
RRef &&r4 = r2; // r4 的类型是 RRef &&,即 int && &&,经过折叠后变为 int &&
LRef &r5 = r2; // r5 的类型是 LRef &,即 int & &&,经过折叠后变为 int &
RRef &&r6 = r1; // r6 的类型是 RRef &&,即 int && &,经过折叠后变为 int &

结合这两个规则,我们就可以理解万能引用的工作原理。例如:

template<class T>
void g(T&& t) {}int x = 10; // x 是左值
g(x); // 调用g时,T被推导为int&(注意不是int),因此t的类型是int& &&// 经过折叠后变为int&(左值)
g(20); // 调用g时,T被推导为int(注意不是int&),因此t的类型是int &&// 经过折叠后仍然是int&&(右值)

你可以看到,在调用g时,t既可以绑定到左值上也可以绑定到右值上,并且保持了原来实参的属性。这就实现了万能引用。

http://www.lryc.cn/news/39949.html

相关文章:

  • 【JavaScript速成之路】JavaScript内置对象--数组对象
  • 【华为机试真题详解 Python实现】最差产品奖【2023 Q1 | 100分】
  • [算法] 二分查找
  • HTML面经
  • 我的十年编程路 2021年篇
  • ElasticSearch 8 学习笔记总结(七)
  • 【云原生】Docker 网络模式详解、容器间网络通信
  • Java开发 - 布隆过滤器初体验
  • 【计算机组成原理 - 第一章】计算机系统概论(完结)
  • C++类与对象(下)【详析】
  • exe反编译为.py文件
  • 38 openEuler搭建FTP服务器-FTP总体介绍
  • 三天吃透操作系统面试八股文
  • vue后台管理系统——添加i18n国际化功能——技能提升
  • 理清gcc、g++、libc、glibc、libstdc++的关系
  • 一、快速入门 MongoDB 数据库
  • PMP第一章到第三章重要知识点
  • 【事务与锁】当Transactional遇上synchronized
  • Pytorch模型转TensorRT步骤
  • 产品经理入门——必备技能之【产品运营】
  • 【Java实现文件上传】java后端+vue前端实现文件上传全过程详解(附源码)
  • 什么是SSD?SSD简述
  • MySQL基础------sql指令1.0(查询操作->select)
  • Python数据分析处理报告--实训小案例
  • OpenCV入门(十二)快速学会OpenCV 11几何变换
  • 小菜鸟Python历险记:(第二集)
  • ContentProvider程序之间数据的相互调用
  • 金三银四最近一次面试,被阿里P8测开虐惨了...
  • 算法题——给定一个字符串 s ,请你找出其中不含有重复字符的最长子串 的长度
  • 机器学习中的数学原理——F值与交叉验证