C++模板元编程(二)——完美转发

news2024/11/16 9:50:41

完美转发指的是函数模板可以将自己的参数“完美”地转发给内部调用的其它函数。所谓完美,即不仅能准确地转发参数的值,还能保证被转发参数的左、右值属性不变。


文章目录

  • 场景
  • 旧的方法
  • 新的方法
  • 内部实现
  • 参考文献


场景

思考下面的代码:

template<typename T>
void function(T t) {
    otherfunc(t);
}

function() 函数模板中调用了otherfunc()函数。我们想要的完美转发是:

  • 如果function()函数接收到的参数 t 为左值,那么该函数传递给 otherfunc() 的参数 t 也是左值。
  • 如果function()函数接收到的参数t为右值,那么传递给 otherfunc() 函数的参数 t 也是右值

显然 function() 函数模板没有实现完美转发,这是因为无论是左值还是右值传递进来,都会当作是左值,因为是非引用类型。

比如 function(10); 传递给 otherfunc() 也是左值而不是我们期望的右值,这在我们期望对左值和右值进行不同处理时会产生问题。


旧的方法

在C++98/03 标准下的 C++ 也可以实现完美转发,只是实现方式比较麻烦。

C++98/03 标准中只有左值引用,可以细分为非 const引用和const引用:

  • 非const引用作为函数模板参数,只能接收左值无法接收右值
  • const左值引用既可以接收左值,也可以接收右值,但如果内部需要将参数传递给其他函数,需要被调用函数的参数也是 const,否则无法直接传递

可见能实现转发,但不够"完美"。

#include <iostream>
using namespace std;
//重载被调用函数,查看完美转发的效果
void otherfunc(int & t) {
    cout << "call lvalue\n";
}
void otherfunc(const int & t) {
    cout << "call rvalue\n";
}

//重载函数模板,分别接收左值和右值
//接收右值参数
template <typename T>
void function(const T& t) {
    otherfunc(t);
}
//接收左值参数
template <typename T>
void function(T& t) {
    otherfunc(t);
}
int main()
{
    function(10);//10 是右值
    int  x = 2;
    function(x);//x 是左值
    return 0;
}

输出为

左值实参既能匹配 function(T& t) 也能匹配 function(const& t),编译器会选择更合适的 function(T& t)


新的方法

对于旧的方法,当模板函数有大量参数的情况,可能就需要编写大量的重载函数模板。

在C++11标准中引入了右值引用,通常情况下右值引用只能接收右值,而对于函数模板中使用右值引用语法定义的参数来说,它既可以接收右值,也可以接收左值(称为万能引用)。

因此在C++11标准中实现完美转发,只需要编写如下一个模板函数即可:

template <typename T>
void function(T&& t) {
	otherdef(t);
}

但是还存在一个问题,如果我们传入的参数是一个左值引用或右值引用的实参,如下所示:

int x = 5;
int& y =  x;
function(y); // T为int&
int&& z = 1;
function(z); // T 为int&&

其中, function(y) 实例化的函数为 function(int& && t),由function(z) 实例化的函数为 function(int&& &&t),这在C++98/03是不支持的,而C++11引入了引用折叠规则:

  • 当实参为左值或者左值引用(A&)时,函数模板中 T&& 将转变为 A&,即 A& && = A&
  • 当实参为右值或者右值引用(A&&)时,函数模板中 T&& 将转变为 A&&,即 A&& && = A&&

还存在的问题是,在function()函数内部,不管是 T& t 还是 T&& t 其实 t 都是一个左值,因此都会传递到 otherfunc(int& t)

所以我们需要一种解决方案来处理这个问题,C++11标准里的模板函数 forward() 就是用来解决这个问题,让我们能传递左值/右值属性,例子如下:

#include <iostream>
using namespace std;
//重载被调用函数,查看完美转发的效果
void otherfunc(int & t) {
    cout << "lvalue\n";
}
void otherfunc(const int & t) {
    cout << "rvalue\n";
}
//实现完美转发的函数模板
template <typename T>
void function(T&& t) {
    otherfunc(forward<T>(t));
}
int main()
{
    function(1);
    int  x = 2;
    function(x);
    return 0;
}

输出如下,正确传递了左值/右值属性


内部实现

下面简单看下内部实现(MSVC)

_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept {
    return static_cast<_Ty&&>(_Arg);
}

_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept {
    static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");
    return static_cast<_Ty&&>(_Arg);
}

简单地来说就是通过静态的强制类型转换+引用折叠,返回对应的结果。

比如下面的四钟情况:

	int x = 2;
	otherfunc(forward<int>(x)); // 匹配第一个,返回 int&&
	otherfunc(forward<int>(2)); // 匹配第二个,返回 int&&
	int& y = x;
	otherfunc(forward<int&>(y)); // 匹配第一个,返回 int&
	int&& z = 2;
	otherfunc(forward<int&&>(z)); // 匹配第一个,返回 int&&,可见右值引用是个左值

它的输出结果如下


参考文献

C++11、C++14、C++17、C++20新特性总结(5万字详解)

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

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

相关文章

哈喽GPT-4o,程序员如何通过GPT-4o提高工作效率

目录 一、编写代码Prompt&#xff1a;请用Java语言编写一个二分查找的样例 二、修正代码错误、代码优化Prompt&#xff1a;我们上传一张华为OD算法题的题目描述&#xff0c;再给它我的Java解题代码&#xff0c;问问它有什么问题&#xff1f; 三、解读代码功能、代码翻译Prompt&…

Qt 网络编程 网络信息获取操作

学习目标&#xff1a;网络信息获取操作 前置环境 运行环境:qt creator 4.12 学习内容 一、Qt 网络编程基础 Qt 直接提供了网络编程模块,包括基于 TCP/IP 的客户端和服务器相关类,如 QTcpSocket/QTcpServer 和 QUdpSocket,以及实现 HTTP、FTP 等协议的高级类,如 QNetworkRe…

flask缓存、信号的使用

【 一 】flask-ache ​ 它为 Flask 应用程序提供了缓存支持。缓存是 Web 应用程序中非常常见的做法&#xff0c;用于存储频繁访问但不太可能经常更改的数据&#xff0c;以减少对数据库或其他慢速存储系统的访问&#xff0c;从而提高应用程序的性能和响应速度。 ​ Flask-Cach…

程序员必知的 89 个操作系统核心概念

1. 操作系统&#xff08;Operating System&#xff0c;OS&#xff09;&#xff1a;是管理计算机硬件与软件资源的系统软件&#xff0c;同时也是计算机系统的内核与基石。操作系统需要处理管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系…

Stable Diffusion 【模型推荐】没有最强,只有更强!高清画质!电影光效版SD1.5人像摄影大模型《他和她 2》

今天带来了一款SD1.5大模型——《他和她 2》电影光效版SD1.5人像摄影大模型。该模型经过家叔马丁Mr_M大佬的优化升级后&#xff0c;把SD1.5的影像光效推上了全新的高度&#xff01;根据大佬的描述&#xff0c;该模型具有更强大的细节表现&#xff0c;更细腻的表面肌理&#xff…

揭秘SmartEDA:电路仿真软件如何贯穿课前课中课后,助力电子学习新纪元!

在电子设计与自动化的学习道路上&#xff0c;一款强大的电路仿真软件往往能为学生们带来事半功倍的效果。今天&#xff0c;我们就来深入探讨一下SmartEDA这款电路仿真软件在课前、课中、课后的全方位应用&#xff0c;看看它如何助力我们的电子学习步入新纪元&#xff01; 1、课…

水果商城系统 SpringBoot+Vue

1、技术栈 技术栈&#xff1a;SpringBootVueMybatis等使用环境&#xff1a;Windows10 谷歌浏览器开发环境&#xff1a;jdk1.8 Maven mysql Idea 数据库仅供学习参考 【已经答辩过的毕业设计】 项目源码地址 2、功能划分 3、效果演示

下载安装JavaFX及解决报错:缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序|Eclipse

目录 1.下载并解压 2.Eclipse配置 3.报错问题 解决方法1&#xff1a;将javaSE更改到9以下 解决方法2&#xff1a; 使用module-info.java配置解决 1.下载并解压 JavaFX下载地址&#xff1a;JavaFX - Gluon 选择合适自己电脑配置的sdk版本下载 打不开网页的参考这个博客&…

泛微开发修炼之旅--35关于基于页面扩展和自定义按钮实现与后端交互调用的方法

文章链接&#xff1a;35关于基于页面扩展和自定义按钮实现与后端交互调用的方法

【手写数据库内核组件】0201 哈希表hashtable的实战演练,多种非加密算法,hash桶的冲突处理,查找插入删除操作的代码实现

hash表原理与实战 ​专栏内容&#xff1a; postgresql使用入门基础手写数据库toadb并发编程 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 文章目录 hash表…

如果国产BI工具也有顶流,它们一定会上榜

在数据驱动的今天&#xff0c;商业智能&#xff08;BI&#xff09;工具已成为企业不可或缺的助手&#xff0c;它们通过强大的数据处理和分析能力&#xff0c;帮助企业洞察市场趋势&#xff0c;优化运营决策。如果BI工具界也有“顶流”&#xff0c;那么奥威BI、帆软BI&#xff0…

世优科技获新锐商业价值奖,数字人阿央入选北京市元宇宙“名人”

2024全球经济大会元宇宙创新发展论坛暨2024第九届“创客中国”元宇宙中小企业创新创业大赛&#xff0c;由工业和信息化部网络安全产业发展中心、北京市经济和信息化局、石景山区人民政府、首钢集团有限公司主办&#xff0c;围绕元宇宙底层技术端和产业应用端两个方向&#xff0…

ROS2 分布式 及 ssh远程控制 和 上传下载文件或文件夹

问题1. 多台计算机连接同一wifi后 &#xff0c;运行ROS2的小乌龟案例&#xff0c;自己的计算机&#xff0c;无法控制其他电脑的小乌龟 按照正常的情况来说&#xff0c;ROS2是DDS的自发现通信机制&#xff0c;只要处在同一wifi网络中&#xff0c; A计算机执行启动小乌龟的命…

计算机网络-组播分发树与组播协议

一、组播分发树 前面我们大致了解了下组播的转发原理&#xff0c;通过RPF反向路径检查可以形成无环的组播转发路径&#xff0c;今天继续学习下组播分发树和组播协议。 组播数据转发需要保证转发路径无环&#xff0c;无次优路径且无重复包。通过RPF机制与组播路由协议&#xff0…

【撤稿资讯】国家杰青被撤稿23篇文章,主要原因图片重复使用等

本周投稿推荐 SCI • 能源科学类&#xff0c;1.5-2.0&#xff08;来稿即录25天&#xff09; • 计算机类&#xff0c;2.0-3.0&#xff08;纯正刊29天录用&#xff09; EI • 各领域沾边均可&#xff08;2天录用&#xff09; 知网 • 7天录用-检索&#xff08;急录友好&a…

论文图片模糊怎么办?科研绘图小track解决你的困扰

论文图片模糊怎么办&#xff1f;科研绘图小track解决你的困扰 一、 使用draw.io 绘图二、使用在线压缩工具&#xff0c;尽可能的无损压缩(推荐迅捷图片转换器)三、当然你也可以用svg 一、 使用draw.io 绘图 网址&#xff1a;https://draw.io/ 解决方法&#xff1a; 加大图片的分…

延时双删两种实现对比分析

前言 延时双删&#xff08;Delayed Double Deletion&#xff09;是一种在分布式系统或缓存一致性处理中使用的技术&#xff0c;目的是确保缓存与数据库之间的数据一致性。它主要用于处理在高并发情况下&#xff0c;缓存和数据库可能出现的数据不一致问题。 常见更新策略的问题…

5分钟微课视频制作方法 微课录制后期制作方法

微课视频是一种短小精悍的在线教育视频形式&#xff0c;通常时长在5到10分钟左右&#xff0c;观众可以在短暂的时间内获取到有用的信息。微课视频的目的是通过简洁明了的内容&#xff0c;向观众传递特定的知识点或技能&#xff0c;它的特点在于紧凑、便于消化和分享&#xff0c…

ESP32CAM物联网教学10

ESP32CAM物联网教学10 MicroPython 应用体验 小智偶然地发现&#xff0c;有一种新兴的编程模式MicroPython&#xff0c;也能编写ESP32Cam的应用程序了&#xff0c;于是欣然地体验了一把。 编程环境搭建 小智偶然地从下面这家店铺买了一块ESP32Cam&#xff0c;并从客服那里得到…

【人工智能】-- 智能家居

个人主页&#xff1a;欢迎来到 Papicatch的博客 课设专栏 &#xff1a;学生成绩管理系统 专业知识专栏&#xff1a; 专业知识 文章目录 &#x1f349;引言 &#x1f349;基于深度卷积神经网络的表情识别 &#x1f348;流程图 &#x1f348;模型设计 &#x1f34d;网络架…