万能引用与完美转发

万能引用与完美转发

    • 万能引用
    • 完美转发
    • 完美转发的应用场景
    • 万能引用的一个小点

万能引用

注意:当&&出现在模板中时,不是右值引用,而是叫万能引用。比如下面的T&& t

template<typename T>
void PerfectForward(T&& t)
{Fun(t);
}

万能引用:

  • 当实参是左值,那么T&& t就是个左值引用

    有些地方,也会叫做引用折叠

    什么意思呢?就是原本形参是T&& t,但比如当实参是个int类型的变量,那么形参这里的模板参数就会变成:int& t。原本两个&&,现在变成一个&。因此形象的称为是引用折叠

  • 当实参是右值,那么T&& t就是个右值引用

为什么会有万能引用呢?归根结底是因为,这里的T是通过形参t推导出来的,假如实参是10,那么T就是int&&;假如实参是int类型的变量,那么T就是int&

完美转发

  • 问题引出

我们看如下代码:

void Fun(int &x){ cout << "左值引用" << endl; }
void Fun(const int &x){ cout << "const 左值引用" << endl; }
void Fun(int &&x){ cout << "右值引用" << endl; }
void Fun(const int &&x){ cout << "const 右值引用" << endl; }template<typename T>
void PerfectForward(T&& t)
{Fun(t);
}int main()
{PerfectForward(10);           // 右值int a;PerfectForward(a);            // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b);            // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}

打印结果:在这里插入图片描述

为什么打印结构都是左值引用呢?第一、三、五不都传的是右值吗?

  • 原因分析

关键问题出在了这里:T&& t

右值引用会被编译器识别为左值。即这里的t是个左值

因此,在void PerfectForward(T&& t)中,实参传递到t中,不论实参是右值还是左值,t始终是个左值。然后再Fun(t);,调用的也当然都是左值引用的函数

  • 深入思考

假如我想要实参是右值t就是右值,实参是左值t就是左值呢?那么就需要用到完美转发

完美转发:在传参的过程中保留对象原生类型属性。完美转发的实现需要用到库里面的函数forward()

也就是说,右值引用会被默认识别为左值,如果想让其保持原本的属性,那么就用完美转发

对上面的例子,加上完美转发后,结果如下:

在这里插入图片描述

完美转发的应用场景

看如下例子:(右值引用中的场景二)

int main()
{list<xy::string> it;it.push_back("111");return 0;
}

C++11之前, 上述代码的调用过程:

在这里插入图片描述

C++11后, “111”是个右值,因此在红框处可以移动拷贝。所以调用过程变成了下面:

在这里插入图片描述

到这里就和我们在右值引用中所讲的过程一样。但是其实上述代码是存在问题的

这是因为:首先"111"传给push_back(T&& x)没有问题,但此时x默认是个左值,然后insert(end(),x)这一调用,并不能调用到右值引用版本的insert,后面的Node(x)也不会调用到右值引用版本的list_node构造函数。所以最终也不是移动拷贝,而是深拷贝

完美转发的出现,很好的解决了上述问题,完美只需如下修改:

在这里插入图片描述

让每个右值引用形参都保留其原本属性,这样最终就可以调用到移动拷贝

万能引用的一个小点

在完美转发的应用场景中:

list_node的构造函数会有两个版本,一个是左值引用的版本,一个是右值引用的版本:

template<class T>
struct list_node
{list_node<T>* _prev;list_node<T>* _next;T _val;list_node(const T& val):_prev(nullptr), _next(nullptr), _val(val){}list_node(T&& val): _prev(nullptr), _next(nullptr), _val(forward<T>(val)){}
};

在万能引用中说到:模板中出现&&不是右值引用,而是万能引用。那这里的list_node(T&& val)是万能引用吗?如果是的话,那么list_node(const T& val)这个左值引用的函数是不是就没有存在的必要了?

其实这里不是万能引用,list_node(const T& val)也不能删去

因为我们说的万能引用最核心的因素在于,模板参数T是可以通过形参val推出来的,而这里的T并不是通过val推导出来的,而是在这里在这里插入图片描述
就确定了的

但是我们只需如下:

template<class T>
struct list_node
{list_node<T>* _prev;list_node<T>* _next;T _val;template<class Ty>list_node(Ty&& val): _prev(nullptr), _next(nullptr), _val(forward<Ty>(val)){}
};

那么就可以使得其变成万能引用(类模板中再用函数模板)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

民宿在线预订系统

摘要 随着国家的发展&#xff0c;人们也更加重视自己的业余时间。在特定的假期或休闲时间外出度假已逐渐成为这个时代的趋势。在我国&#xff0c;随着经济的发展和城市居民物质生活水平的提高&#xff0c;旅游业也呈现出越来越受欢迎的趋势。同时随着人口的快速流动&#xff0…

jQuery事件和其他方法

&#xff08;2&#xff09;jQuery 事件处理 2.1 事件处理 on() 绑定事件 on() 方法在匹配元素上绑定一个或多个事件的事件处理函数&#xff1b; 语法演示如下&#xff1a; element.on(events,[selector],fn)&#x1f606;温馨提醒&#x1f606;&#xff1a; events&#xff…

Leetcode 522. 最长特殊序列 II (判断子序列 优化)

Leetcode 522. 最长特殊序列 II 暴力枚举 根据特殊序列的定义&#xff0c;枚举出每个 strs[ i ] 的所有子序列&#xff0c;再将这个子序列与strs中的其他串比较判断 使用二进制位运算枚举一个str的所有子序列 使用双指针指向两个串的开头&#xff0c;同时移动判断是否是子序列…

代理网络基础设施 101:增强安全性、速度和可扩展性

编辑代理网络在现代网络架构中发挥着重要作用&#xff0c;充当管理和重新路由数据流的中介。它们处理的数据可以是各种类型&#xff0c;包括搜索查询和潜在的敏感客户信息&#xff0c;这凸显了它们在数据安全方面的作用。 然而&#xff0c;代理的好处不仅限于安全性。它们为用…

类AAAAAAAAAAAA迭代

class A {vector<A>} C 迭代 这个代码在C中是不能编译的&#xff0c;因为它会导致无限的嵌套&#xff0c;因为std::vector<A>会持有A类型的实例&#xff0c;而A类型的实例又会包含一个std::vector<A>&#xff0c;这会无限制地复制和嵌套下去。 如果你想要创…

linux中如何进行yum源的挂载

linux中如何进行yum源的挂载 ​ 1.首先创建目录[rootserver /]# mkdir /rhel92.使用mount命令进行、dev/cdrom/的镜像文件进行挂载[rootserver /]# mount /dev/cdrom /rhel9/ ​ 注意&#xff1a;此时设立的是临时命令。重启后则失效&#xff0c;若想在下次开启后仍然挂载&a…

WPF由文本框输入的内容动态渲染下拉框

在做项目过程中&#xff0c;需要扫码枪扫描快递单号或者手动输入快递单号时&#xff0c;自动检索该单号是哪个快递公司的&#xff0c;下拉框中自动带出该单号的快递公司。当输入的快递单号不存在时&#xff0c;将数据库中所有快递公司都带出 效果&#xff1a; 通过输入的快递单…

人工智能与生物信息组学 || 2. 非编码 RNA 与疾病关联分析 || 2.2 非编码 miRNA 与疾病关联关系预测

非编码 miRNA 与疾病关联关系预测 越来越多的研究表明&#xff0c;一个复杂疾病通常经由多个 miRNA 协同调控&#xff0c;一个 miRNA 通常参与多个疾病的发生发展过程。因此&#xff0c;预测 miRNA 与疾病的关联关系成为一个当前的研究热点。下面我们将探讨一种 miRNA 和疾病关…

技术驱动会展:展位导航系统的架构与实现

随着会展行业的快速发展&#xff0c;大型会展中心面临着如何提升参展者体验、提高招商效率的挑战。针对客户反馈的展馆面积大、展位查找困难等问题&#xff0c;维小帮提出一套智慧会展导航解决方案&#xff0c;旨在通过先进的室内导航技术提升会展中心的运营效率和参展者的满意…

How to atomically update a maximum value?

c - How to atomically update a maximum value? - Stack Overflow

小阿轩yx-MySQL数据库初体验

小阿轩yx-MySQL数据库初体验 数据库简介 21 世纪迈入了“信息爆炸时代”&#xff0c;大量的数据、信息在不断产生&#xff0c;伴随而来的就是如何安全、有效地存储、检索和管理它们。 对数据的有效存储、高效访问、方便共享和安全控制已经成为信息时代亟待解决的问题。 使用…

【杂记-浅谈OSPF协议中的Router ID】

这里写目录标题 一、OSPF协议要素1、COST值2、进程号3、路由及路由器类型4、区域及网络类型5、DR和BDR6、STUB和NSSA区域7、邻居状态机 二、OSPF路由协议中各功能1、报文认证2、路由聚合3、缺省路由4、路由过滤5、多进程6、路由计算7、最小生成树 一、OSPF协议要素 1、COST值 …

QThread 与QObject::moveToThread在UI中的应用

1. QThread的两种用法 第一种用法就是继承QThread&#xff0c;然后覆写 virtual void run()&#xff0c; 这种用法的缺点是不能利用信号槽机制。 第二种用法就是创建一个线程&#xff0c;创建一个对象&#xff0c;再将对象moveToThread, 这种可以充分利用信号槽机制&#xff…

Python中元组的常用方法

元组的基本使用 t (1, 2, 3) print(t)统计元组元素出现的次数 t (11, 11, 22, 22, 33, 33, 33, 33, 33) print(t, type(t))print(t.count(33))元组的遍历 t (1, 2, 3)for i in t:print(i)print("-" * 33) for i in range(len(t)):print(t[i])print("-&quo…

c,c++,qt从入门到地狱

前言 1 你所能用的正与你手写的效率相同2 你不需要为你没有用到的特性付出 (无脑的调用函数or公式的空壳人类请出门右转)c 001 scanf and strcpy "_s"bug? 微软官方说明1 Visual Studio 库中的许多函数、成员函数、函数模板和全局变量已弃用,改用微软新增的强化函数…

P3056 [USACO12NOV] Clumsy Cows S

[USACO12NOV] Clumsy Cows S 题目描述 Bessie the cow is trying to type a balanced string of parentheses into her new laptop, but she is sufficiently clumsy (due to her large hooves) that she keeps mis-typing characters. Please help her by computing the min…

RK3588 开启HDCP

主题&#xff1a;按照文档配置无法使能HDCP1.4、HDCP2.3 描述&#xff1a; 按照文档配置无法使能HDCP1.4、HDCP2.3,具体操作如下&#xff1a; 1、dts使能使能hdcp1节点&#xff1a; &hdcp1 { status "okay"; }; 2、DWC_HDCP2_BASE_ESM_Firmware 解压…

浅析Node.js中http代理的实现

文章目录 前言ReadableStream和WritableStreamreq.pipe小结 前言 起因是狼书卷1中的API Proxy例子&#xff0c;代码如下&#xff1a; const http require(http) const fs require(fs)const app http.createServer((req, res) > {if (/remote req.url) {res.writeHead(…

canal 服务安装

简介&#xff1a;Canal 是阿里巴巴开源的一个基于 MySQL 数据库增量日志解析的中间件&#xff0c;用于提供准实时的数据同步功能。 准备工作 1.修改配置文件 ,需要先开启 Binlog 写入功能&#xff0c;配置 binlog-format 为 ROW 模式&#xff0c;my.cnf 中配置如下&#xf…

五种实用方法!手把手教你系统盘瘦身

随着电脑的使用时间变长&#xff0c;电脑硬盘会逐渐被各种类型的数据占满&#xff0c;其中系统盘的可用空间也在慢慢变小。这是因为系统在运行过程中会产生大量临时文件和缓存文件&#xff0c;同时&#xff0c;系统的每一次更新升级也都会生成相关的文件夹存放在系统盘中&#…