【模板进阶】模板的万能引用

一、类型的区别和基本定义

1.1类型的基本定义

首先先看一个最简单例子:

//类型的区别和基本定义
void func(const int& abc) { } //abc的类型为const int&

这里的 a b c abc abc被推导为什么类型? 显然可见,为 c o n s t i n t & const \ int\& const int&类型,上面不都写着呢!


然后,我们在看看一个简单的模板:

template<typename T>
void func(const T& abc) {}void Test1() {func(10); //T为int,abc为const int&
}

这里传入的 10 10 10显然是转换为了 i n t int int类型,那么 T = i n t , a b c = c o n s t i n t & T = int,abc = const\ int\& T=int,abc=const int&,这是容易推导出来的。


二、万能引用的基本认识

U n i v e r s a l R e f e r e n c e Universal \ Reference Universal Reference后来被称为 F o r w a r d i n g R e f e r e n c e ( 转发引用 ) Forwarding \ Reference \ (转发引用) Forwarding Reference (转发引用),翻译成中文有好几种方式,这里我们采用一种最常用的名称:“万能引用”。

万能引用这个概念是许多概念的基础,所以这里率先将这个概念阐述清楚。首先记住一个结论:

万能引用是一种类型。就跟int是一种类型一个道理,再次强调,万能引用,是一种类型。

2.1右值引用

万能引用和右值引用形式上长得相似,但实际上是两种类型,这里先介绍一下右值引用。


我们知道,右值是绑定在用 & & \&\& &&符号表示,主要是用于绑定右值,如:

//右值引用
void myfunc(int&& tmpr) {std::cout << tmpr << "\n";}

测试一下:

void Test2() {myfunc(10); //正确,右值int i = 100;myfunc(i); //错误,左值无法绑定到右值引用上
}

这里,容易发现, m y f u n c ( i ) myfunc(i) myfunc(i)这一行编译失败了,原因就是右值引用无法绑定在左值上。


2.2 万能引用

这里,我们改造一下 m y f u n c myfunc myfunc函数,把它写成一个函数模板:

template<typename T>
void myfunc(T&& tmpr) { std::cout << "调用了函数模板:" << tmpr << "\n";
}

然后我们再同样调用相同的函数:

void Test2() {myfunc(10); //正确,右值int i = 100;myfunc(i); //编译成功
}

可以发现,此时编译成功了。


现在,我们看到的事实有两条:

( 1 ) (1) (1)这里的函数模板中的 t m p r v tmprv tmprv参数能接受左值(作为实参),也能接受右值;
( 2 ) (2) (2) t m p r v tmprv tmprv的类型是 T & & T\&\& T&&(这两个地址符是属于 t m p r v tmprv tmprv的),编译都没报错。

实际上,这里使用到的就是万能引用,这里的 T T T类型在传入左值或者右值的时候,会被推断为不同的类型,通用编译期的折叠引用最终推断出正确的引用类型来接受参数。


同时,这里的引用类型是能够被修改的,如下:

//万能引用
template<typename T>
void myfunc(T&& tmpr) { std::cout << "调用了函数模板:" << tmpr << "\n";tmpr = 0; //tmpr是左值,可以被修改
}
void Test1(){myfunc(i); //正确,万能引用std::cout << i << "\n";i = 200;myfunc(std::move(i));std::cout << i << "\n";}

我们调用一下,可以发现无论是左值还是右值,都可以被修改,因为接收实参的形参本身是一个左值,它可以被修改:

在这里插入图片描述


万能引用 ( U n i v e r s a l R e f e r e n c e ) (Universal Reference) (UniversalReference)又称为未定义引用,这种引用离不开上面提到的两种语境,这两种语境必须同时存在:

( 1 ) (1) (1)必须是函数模板;
( 2 ) (2) (2)必须是发生了模板类型推断并且函数模板形参形如 T & & T\&\& T&&


万能引用的格式为&T&&&。它也用两个地址符号 & & \&\& &&表示,所以,万能引用的形式就与右值引用一模一样。但是解释起来却不一样(注意语境,只有在语境满足的条件下,才能把 & & \&\& &&解释为万能引用而不是往右值引用)。

( 1 ) (1) (1)右值引用作为函数形参时,实参必须传递右值进去,不然编译器报错,上面已经看到了。

( 2 ) (2) (2)而万能引用作为函数形参时,实参可以传递左值进去,也可以传递右值进去。所以,万
能引用叫作未定义引用。如果传递左值进去,那么这个万能引用就是一个左值引用;如果传递右值进去,那么这个万能引用就是一个右值引用。从这个角度来讲,万能引用更厉害,是一种中性的引用,可以摇身一变,变成左值引用;也可以摇身一变,变成右值引用。


三、万能引用的辨认

万能引用和右值引用通常很相似,我们下面举几个例子来讨论一下:


3.1 例子1

这是右值引用,万用引用必须在模板的条件下:

//右值引用
void myfunc(int&& tmpr) {std::cout << tmpr << "\n";}

3.2 例子2

这是右值引用,因为在类模板实例化的同时, T T T也就被确认了,因此是右值引用

template<typename T>
class myclass {
public:void func(T&& tmpr) { //不是万能引用std::cout << tmpr << "\n";}
};

3.3 例子3

这个是万能引用,这里的 U U U类型是独立的,不受类模板的影响

template<typename T>
class myclass {
public:template<typename U>void func2(U&& tmpr) { //万能引用std::cout << tmpr << "\n";}
};

3.4 例子4

形如 a u t o & & auto \&\& auto&&的也是万能引用:

//万能引用
template<typename T>
void myfunc(T&& tmpr) {auto&& tmpr2 = tmpr; //万能引用std::cout << "调用了函数模板:" << tmpr << "\n";}

四、万能引用资格的剥夺

4.1剥夺

如果在万能引用中使用 c o n s t const const修饰,那么这个万能引用资格就会被剥夺,从而退化为右值引用,例如:

//剥夺template<typename T>
void myfunc_const(const T&& tmpr) { //退化为右值引用std::cout << tmpr << "\n";//tmpr = 0; //const修饰不能被修改
}void Test4() {int i = 100;//myfunc_const(i); //错误,只能传入右值myfunc_const(std::move(i)); //std::move转为右值std::cout << i << "\n";
}

这时,我们 m y f u n c _ c o n s t ( i ) myfunc\_const(i) myfunc_const(i)就会编译错误,因为此时已经是右值引用了。并且由于 c o n s t const const的修饰,我们无法在函数内修改参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1539445.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

mysql使用sql函数对json数组的处理

MySQL从5.7版本开始增加了对JSON数据类型的支持。你可以使用->>操作符和JSON_EXTRACT函数来访问JSON数据中的值。 但是&#xff0c;对于JSON数组&#xff0c;如果你想要获取数组中的所有元素&#xff0c;MySQL并没有直接的函数来返回数组中的所有元素作为单独的行。不过…

PDF产品册营销推广利器FLBOOK

在互联网高速发展的时代&#xff0c;营销推广已成为企业拓展市场的重要手段。而一款优秀的营销工具&#xff0c;可以为企业带来事半功倍的推广效果。今天&#xff0c;就为大家介绍一款集创意与实用于一体的PDF产品册营销推广利器——FLBOOK&#xff0c;帮助企业轻松提升品牌影响…

算法-查找算法(顺序查找二分查找)

3.查找算法 查找也称为搜索&#xff0c;就是从数据中找出满足特定条件的元素。 常见的查找算法&#xff1a;顺序查找、二分查找。 3.1 顺序查找算法 顺序查找算法又称为线性查找&#xff0c;是一种比较简单的查找算法&#xff0c;是将数据一项一项的按照顺序逐个查找&#x…

电力电容器、电子电容器的区别

电力电容器和电子电容器在用途、结构、工作环境以及电气性能等方面有显著的区别。以下是它们的主要区别&#xff1a; 1、用途和应用场景 电力电容器&#xff1a; 主要用于电力系统中&#xff0c;主要功能是进行无功功率补偿&#xff0c;提高功率因数&#xff0c;改善电网的电…

mybatisplus介绍以及使用(上)

目录 一、概念 1、什么是mybatisplus 2、为什么要使用mybatisplus 二、mybatisplus的使用 1、安装 2、常用注解 3、条件构造器 一、概念 1、什么是mybatisplus MyBatis-Plus&#xff08;简称MP&#xff09;是一个基于MyBatis的增强框架&#xff0c;旨在简化开发、提高…

云端启航,探索微生物奥秘——美格基因云组学分析全新升级!

在这个信息爆炸的时代&#xff0c;我们深知高效的数据处理对于科研的重要性。为了帮助您更好地挖掘微生物世界的无限可能&#xff0c;美格基因凭借在弹性云计算领域的深厚积累&#xff0c;构建了一个强大的云生态系统。这一系统不仅整合了云组学、云工具、云数据库、前沿工具等…

人脸活体检测系统源码分享

人脸活体检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

Spring底层架构源码解析(三)

目录 ApplicationContext AnnotationConfigApplicationContext ClassPathXmlApplicationContext 类型转换 PropertyEditor ConversionService BeanPostProcessor FactoryBean MetadataReader、ClassMetadata、 AnnotationMetadata ExcludeFilter&#xff0c;Inclu…

【2025】基于微信小程序的人工智能课程学习平台的设计与实现(源码+文档+解答)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

如何使用ssm实现企业文档管理系统+vue

TOC ssm648企业文档管理系统vue 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。…

htop(1) command

文章目录 1.简介2.格式3.选项4.交互式命令5.示例6.小结参考文献 1.简介 htop 是一种交互式、跨平台的基于 ncurses 的进程查看器。 类似于 top&#xff0c;但 htop 允许您垂直和水平滚动&#xff0c;并使用指向设备(鼠标)进行交互。您可以观察系统上运行的所有进程&#xff0…

关于支持向量机的一份介绍

在这篇文章中&#xff0c;我将介绍与支持向量机有关的东西&#xff0c;我们知道支持向量机主要分两类&#xff0c;就是线性支持向量机和核支持向量机这两种&#xff08;当然还有其他的&#xff0c;如多类支持向量机、 Nu-Support Vector Regression等&#xff09;&#xff0c;因…

docker存储

docker分层结构 如图所示&#xff0c;容器是由最上面可读可写的容器层&#xff0c;以及若干个只读镜像层组成&#xff0c;创建容器时&#xff0c;容器中的 数据都来自镜像层。这样的分层机构最大的特点是写时复制&#xff1a; 1、容器中新生成的数据会直接存放在容器层&#xf…

产品经理入门攻略:如何从零开始成为产品经理

“人人都是产品经理”这句话相信你一定听过。 作为现在的热门职业&#xff0c;许多朋友也在心里埋下了一颗想要成为产品经理的种子。 产品经理的工作其实没有传说中的那么“高大上”&#xff0c;甚至可以说大多数时候是枯燥且无聊的&#xff0c;需要不断地对数据进行分析&…

第十一章 【后端】商品分类管理微服务(11.5)——增强响应

11.5 增强响应 在前后端分离的开发模式下,我们一般会统一后端的响应格式,比如自定义 Response 结构,但每个开发者可能会封装各自的 Response 结构,造成不一致,因此我们需要将响应格式统一起来,定义一个统一的标准响应格式。 11.5.1 创建响应模块 新建 yumi-etms-respon…

高效实现业务流程管理的技术——低代码解决方案

一、低代码平台概述 低代码平台允许用户通过可视化的界面设计和配置应用程序&#xff0c;而无需深入编程知识。这种平台通常包括拖拽式的组件、流程图设计工具、以及预设的功能模块&#xff0c;使得业务用户和开发者都能快速构建和修改应用程序。 二、低代码平台在 BPM 中的优…

动手学深度学习PyTorch 第 1 章 引言

在线电子书 深度学习介绍 安装 使用conda环境 conda create -n d2l-zh python3.8 pip安装需要的包 pip install jupyter d2l torch torchvision下载代码并执行 wget https://zh-v2.d2l.ai/d2l-zh.zip unzip d2l-zh.zip jupyter notebookpip install rise如果不想使用jupyt…

ubuntu20.04安装cudnn

先登入账号 网址&#xff1a;https://developer.nvidia.com/cudnn 选择ubuntu20.04 x86_64&#xff08;Deb&#xff09; 在下载好文件的文件夹下打开终端 sudo apt-get install zlib1gsudo dpkg -i cudnn-local-repo-${distro}-8.x.x.x_1.0-1_amd64.debsudo cp /var/cudnn-lo…

【终极对决】Ping32 vs 绿盾:十大维度深度剖析,谁是企业数据安全的守护神?

在信息安全领域&#xff0c;企业对数据保护的需求不断升级。Ping32与绿盾加密作为两款备受关注的数据保护软件&#xff0c;各具特色。本文将从十大维度深度剖析这两款软件&#xff0c;帮助企业选择最适合自己的数据安全解决方案。 1. 加密算法 Ping32 Ping32采用了多种高级加…

Tiny Universe - Llama3架构

Llama3和Llama2和Qwen2的整体架构相似&#xff0c;本篇文章主要讲解它们的一些主要不同点。 关于Qwen2架构可参考 Qwen2架构 学习笔记 llama3区别于llama2在模型层面的区别主要体现在全模型使用GQA。 基础知识 MLP MLP&#xff08;Multi-Layer Perceptron&#xff09;多层感…