C++ 11新特性之完美转发

概述

        在C++编程语言的演进过程中,C++ 11标准引入了一系列重大革新,其中之一便是“完美转发”机制。这一特性使得模板函数能够无损地传递任意类型的实参给其他函数或构造函数,从而极大地增强了C++在泛型编程和资源管理方面的灵活性与效率。

        完美转发的目标是在模板函数中保持原始参数的所有属性(比如:左值、右值、const/volatile限定等),确保无论传入的是什么类型的参数,都能够正确地传递到后续的函数调用中。这在处理具有复杂类型和引用性质的函数参数时显得尤为重要,尤其是在需要保持移动语义的情况下。

        在C++ 98/03标准下,模板参数默认为非引用类型,导致无法直接传递左值引用或者右值引用。同时,由于模板参数推导规则的限制,对于左值引用参数,即使使用typename T&也无法区分出右值引用。因此,为了实现完美转发,C++ 11引入了万能引用和std::forward函数。

万能引用和std::forward

        万能引用是指形如T&&的模板参数,在某些情况下可以接受任何类型的引用。这里的T会根据实参的实际类型进行推导,因此,它可以是左值引用也可以是右值引用。当模板参数T被绑定到一个具体的左值上时,T&&会成为一个左值引用。而当它被绑定到右值或者临时对象时,T&&则会成为右值引用。

        std::forward<T>(arg)是一个用于完美转发的关键工具,它负责维护实参原有的左值/右值引用属性,并在必要时强制转换为右值引用以便执行移动操作。

        在完美转发场景中,通常结合万能引用和std::forward来编写模板函数,以达到无损传递参数的目的。

        在下面的示例代码中,Forward模板函数接受一个参数T&& arg,这里的T&&在特定情况下被称为万能引用。在模板实例化时,编译器会根据传入的实际参数类型推断T。如果传入的是左值,则T会被推断为左值引用类型;如果传入的是右值,则T会被推断为非引用类型(即右值引用会退化成普通类型)。因此,在函数内部,arg可以是任何类型的左值引用或右值。

        Forward函数体内部调用了Process函数,并通过std::forward<T>(arg)将arg无损地传递给Process函数。std::forward的作用是保持实参原有的左值/右值性质不变,这样当arg被传递给Process时,它仍然保持着原来的引用属性。

        在main函数中,当调用Forward(nNumber)时,因为nNumber是一个左值,所以T被推断为int&类型,也就是说arg在这里是一个int&类型的引用,指向变量nNumber。而当调用Forward(66)时,因为66是一个右值常量表达式,所以T被推断为int类型,arg成为一个右值引用(由于传入的是右值,此时实际上是隐式转换为了右值引用int&&),指向一个临时创建的整数对象。

#include <iostream>
using namespace std;template<typename T>
void Process(T arg)
{cout << arg << endl;
}template<typename T>
void Forward(T &&arg)
{// arg是一个万能引用,可以绑定到左值或右值Process(std::forward<T>(arg));
}int main()
{int nNumber = 66;// 在这里,T被推断为int&,arg绑定到左值xForward(nNumber);// 在这里,T被推断为int&&,arg绑定到右值临时对象Forward(66);return 0;
}

应用场景

        在C++中,完美转发常用于编写通用工厂函数,使得该函数能够接受任意类型和引用类型的参数,并无损地传递给目标构造函数。

#include <iostream>
#include <memory>
using namespace std;template<typename T, typename... Args>
std::unique_ptr<T> CreateObject(Args&&... args)
{return std::make_unique<T>(std::forward<Args>(args)...);
}class MyClass
{
public:MyClass(int a, const std::string& b) {}MyClass(const MyClass& other) {}MyClass(MyClass&& other) noexcept {}
};int main()
{auto obj1 = CreateObject<MyClass>(66, "CSDN");return 0;
}

        在上面的示例代码中,CreateObject函数接收任意数量、任意类型的参数(通过模板参数包Args表示),并使用std::forward<Args>(args)...将这些参数无损地传递给T类型的构造函数。这意味着无论是左值还是右值,甚至是具有特定CV限定符的引用,都能正确地传递给目标构造函数。

        当调用CreateObject<MyClass>(66, "CSDN")时,实参66(右值)和"CSDN"(左值引用)会被完美地转发给MyClass的构造函数。如果传入的是右值临时对象,编译器会自动选择移动构造函数。如果是左值引用或普通值,则根据构造函数签名匹配相应的构造方式。

总结

        C++ 11引入的完美转发特性在提升代码的灵活性、简洁性和效率方面发挥了关键作用,特别是在现代C++中,开发者必须充分理解和熟练运用这一技术,才能编写出更加高效、可扩展的泛型代码。随着C++版本的不断更新,完美转发已经成为构建高性能库、设计组件化架构及编写高质量应用程序的重要基石。

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

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

相关文章

探究HMAC算法:消息认证与数据完整性的完美结合

Hash-based Message Authentication Code&#xff08;基于哈希的消息认证码&#xff0c;简称HMAC&#xff09;算法作为一种广泛应用的消息认证码&#xff08;MAC&#xff09;算法&#xff0c;在现代信息安全领域起着至关重要的作用。本文将从算法原理、优缺点、实际应用等方面&…

20240128周报-网络太杂,Tomcat太难

今天来做个小总结吧&#xff0c;之前说想用几个月的时间将Java生态给整理一遍&#xff0c;该工作已经进入第三周了。先和各位老老板汇报一下上一周的工作&#xff0c;然后说一下本周的计划和后面的计划。 1.上周工作 上周的计划是将网络和Tomcat的内容梳理一番&#xff0c;但…

亚马逊要怎么运营?亚马逊运营主要运营内容有哪些?

一个店铺的成长发展少不了运营&#xff0c;而店铺的运营必须要有相关运营经验&#xff0c;才能将店铺做好&#xff0c;近几年亚马逊电商平台在不断的发展&#xff0c;亚马逊的运营模式非常独特&#xff0c;它借助于多种技术解决方案来提供最佳的客户体验。那么亚马逊要怎么运营…

你的MiniFilter安全吗?

简介 筛选器管理器 (FltMgr.sys)是Windows系统提供的内核模式驱动程序, 用于实现和公开文件系统筛选器驱动程序中通常所需的功能; 第三方文件系统筛选器开发人员可以使用FltMgr的功能可以更加简单的编写文件过滤驱动, 这种驱动我们通常称为MiniFilter, 下面是MiniFilter的基本…

python21-Python的字符串查找、替换相关方法

str还提供了如下常用的执行查找、替换等操作的方法。 startswith():判断字符串是否以指定子串开头。 endswith():判断字符串是否以指定子串结尾 find():查找指定子串在字符串中出现的位置&#xff0c;如果没有找到指定子串&#xff0c;则返回-1。 index():查找指定子串在字…

Java多线程--解决单例模式中的懒汉式的线程安全问题

文章目录 一、单例设计模式的线程安全问题&#xff08;1&#xff09;饿汉式没有线程安全问题&#xff08;2&#xff09;懒汉式线程安全问题1、案例2、方式1-同步方法3、方式2-同步代码块4、优化 二、代码&#xff08;1&#xff09;实现线程安全的懒汉式&#xff08;2&#xff0…

猫什么时候发腮?公认发腮效果好的生骨肉冻干推荐

猫什么时候发腮是许多猫主人非常关心的问题。在猫咪的成长过程中&#xff0c;发腮是一项重要的体征&#xff0c;也是猫咪成熟的标志。想要让猫咪拥有可爱的肉嘟嘟脸型&#xff0c;主人需要在适龄的年龄段加强营养补给&#xff0c;不要错失最佳发腮期。那么&#xff0c;猫咪的最…

pytorch交换数组元素坑

写 PermutePatch 时遇到一个 bug&#xff1a;在试图交换 PyTorch 数组的两个元素时&#xff0c;两个位置都变成同一个元素&#xff01;具体见测试代码。本文兼测几种交换情况&#xff1a; 两个 python 变量list 两个元素numpy 数组两个元素pytorch 数组两个元素 import numpy…

api接口1688商品详情接口采集商品详情数据商品价格详情页数据可支持高并发调用演示示例

接入1688商品详情API接口的步骤如下&#xff1a; 注册账号&#xff1a;首先&#xff0c;你需要在1688开放平台注册一个账号。 创建应用&#xff1a;登录后&#xff0c;在控制台中找到“我的应用”&#xff0c;点击“创建应用”。 获取API密钥&#xff1a;创建应用后&#xff…

【Linux】VMware Workstation16安装银河麒麟高级服务器操作系统V10 SP3 AMD64

目录 一、麒麟服务器概述 二、安装步骤 设置硬盘大小 完成配置 修改内存 处理器等设备配置 选择直接安装 配置磁盘 网络配置 设置root账号密码 开始安装 启动完成 一、麒麟服务器概述 银河麒麟高级服务器操作系统V10是针对企业级关键业务&#xff0c;适应虚拟化、云…

Android开发之动画

逐帧动画 通过在连续的帧之间快速切换来创建动画效果 var anim animationView.background as AnimationDrawable获取动画的Drawable资源anim.start()启动动画anim.stop()停止动画 private lateinit var animationView: ImageView private var flag: Boolean trueanimation…

C语言KR圣经笔记 6.8联合体 6.9位域

6.8 联合体&#xff08;union&#xff09; 联合体是一个可以&#xff08;在不同时间&#xff09;保存不同类型和大小的对象的变量&#xff0c;由编译器来跟踪大小和对齐要求。联合体提供了一种不用在程序中嵌入任何与机器相关的信息&#xff0c;而能够在单个存储区域内操作不同…

时间序列预测——GRU模型

时间序列预测——GRU模型 在深度学习领域&#xff0c;循环神经网络&#xff08;RNN&#xff09;是处理时间序列数据的一种常见选择。上期已介绍了LSTM的单步和多步预测。本文将深入介绍一种LSTM变体——门控循环单元&#xff08;GRU&#xff09;模型&#xff0c;包括其理论基础…

Flutter canvas 画一条会动的波浪线 进度条

之前用 Flutter Canvas 画过一个三角三角形&#xff0c;html 的 Canvas 也画过一次类似的&#xff0c; 今天用 Flutter Canvas 试了下 感觉差不多&#xff1a; html 版本 大致效果如下&#xff1a; 思路和 html 实现的类似&#xff1a; 也就是找出点的位置&#xff0c;使用二阶…

DAY37:贪心算法738

今天写了一道题目&#xff0c;顺便看了一个很好的总结&#xff0c;这篇博客可以跳过。 Leetcode&#xff1a;738 单调递增的数字 因为最大的数字是9&#xff0c;当出现后面位数的数字比前面位数的数字小的时候&#xff0c;就把后面的数字都变成9&#xff0c;前面那个数字--。…

网安面试指南——(渗透,攻击,防御)

网安面试 目录 1.什么是 WebShell? 2.什么是网络钓鱼&#xff1f; 3.你获取网络安全知识途径有哪些&#xff1f; 4.什么是 CC 攻击&#xff1f; 5.Web 服务器被入侵后&#xff0c;怎样进行排查&#xff1f; 6.dll 文件是什么意思&#xff0c;有什么用&#xff1f;…

Cannot assign to read only property ‘exports‘ of object ‘#<Object>‘

看下多语言js文件中&#xff0c;是否同级出现相同名称。

3D 转换

1&#xff0c;3D的特点&#xff1a; 近小远大 物体后面遮挡不可见 2&#xff0c;3D移动 translate3d 3D移动在2D移动的基础上多加了一个可以移动的方向&#xff0c;就是z轴方向 transform&#xff1a;translateX&#xff08;100px&#xff09;&#xff1a;仅仅是在x轴上移动…

mysql8.0主从搭建

一、架构说明 MySQL 主从架构是一种常见的数据库部署方案&#xff0c;用于实现数据的自动同步和冗余备份。在该架构中&#xff0c;主服务器负责处理事务的写入操作&#xff0c;从服务器则负责复制主服务器上的数据&#xff0c;并可以用于读取操作&#xff0c;以减轻主服务器的…

寒假刷题第19天

PTA甲级 1134 Vertex Cover #include<iostream> #include<vector> #include<set>using namespace std;typedef pair<int , int> PII; vector<PII>v; int n , m;bool check(set<int>&se) {for(auto i : v)if(!se.count(i.first) &…