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

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


文章目录

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


场景

思考下面的代码:

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.mzph.cn/diannao/42362.shtml

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

相关文章

专业140+总分420+天津大学815信号与系统考研经验天大电子信息与通信工程,真题,大纲,参考书。

顺利上岸天津大学&#xff0c;专业课815信号与系统140&#xff0c;总分420&#xff0c;总结一些自己的复习经历&#xff0c;希望对于报考天大的同学有些许帮助&#xff0c;少走弯路&#xff0c;顺利上岸。专业课&#xff1a; 815信号与系统&#xff1a;指定教材吴大正&#xf…

2-26 基于matlab开发的制冷循环模型

基于matlab开发的制冷循环模型。Simscape两相流域中的制冷循环模型&#xff0c;在simulink中完成多循环温度控制。程序已调通&#xff0c;可直接运行。 2-26 制冷循环模型 Simscape两相流域 - 小红书 (xiaohongshu.com)

Arduino ESP8266 开发环境搭建

Arduino ESP8266 开发环境搭建 很久之前学嵌入式时&#xff0c;用过Arduino8266进行开发&#xff0c;开发成本低、难度小&#xff0c;体验很不错。 近期&#xff0c;又突然要用&#xff0c;遂再次搭建环境&#xff0c;但变动挺多&#xff0c;有些小波折&#xff0c;开贴记录。…

高考志愿填报千万要注意这四点

在高考志愿填报过程中&#xff0c;确实有很多需要留心的点。我为你总结了四个关键点&#xff0c;希望能帮助你顺利完成志愿填报&#xff1a; 1、学校提供的支持 学校作为学生志愿填报咨询服务的主阵地&#xff0c;应提供体系化和制度化的支持。包括及时关注并传达政策动向和相…

行内元素、块级元素居中

行内元素居中 水平居中 {text-align&#xff1a;center;}垂直居中 单行——行高等于盒子高度 <head><style>.father {width: 400px;height: 200px;/* 行高等于盒子高度&#xff1a;line-height: 200px; */line-height: 200px;background-color: pink;}.son {}&…

如何做好IT类的技术面试?

我们在找工作时&#xff0c;需要结合自己的现状&#xff0c;针对意向企业做好充分准备。作为程序员&#xff0c;你有哪些面试IT技术岗的技巧&#xff1f; 方向一&#xff1a;分享你面试IT公司的小技巧 我分享一些基于广泛观察和用户反馈的面试IT公司的小技巧&#xff1a; 技术准…

孟德尔随机化-痛风

写在前面 昨天看到文献&#xff0c;称饮酒与痛风无关联&#xff0c;甚是疑惑&#xff0c;今天刚好看了一篇新文献&#xff0c;虽然不是主要讲饮酒与痛风的&#xff0c;但也有牵扯到这方面内容&#xff0c;而且是相反的内容&#xff0c;特记录一下。 孟德尔随机化-受教育程度与…

vuepress创建步骤

背景 记录vuepress配置步骤&#xff0c;以便下次使用快速上手。 读此文章之前默认您已经学会了创建vuepress项目。vuepres快速开始 最终成品 doc.jeecgflow.com 配置步骤 创建.vuepress 目录。 你的文档目录下创建一个 .vuepress 目录。 创建.vuepress/config.js module.e…

Mac窗口辅助管理工具:Magnet for mac激活版

magnet mac版是一款运行在苹果电脑上的一款优秀的窗口大小控制工具&#xff0c;拖拽窗口到屏幕边缘可以自动半屏&#xff0c;全屏或者四分之一屏幕&#xff0c;还可以设定快捷键完成分屏。这款专业的窗口管理工具当您每次将内容从一个应用移动到另一应用时&#xff0c;当您需要…

注意力机制 attention Transformer 笔记

动手学深度学习 这里写自定义目录标题 注意力加性注意力缩放点积注意力多头注意力自注意力自注意力缩放点积注意力&#xff1a;案例Transformer 注意力 注意力汇聚的输出为值的加权和 查询的长度为q&#xff0c;键的长度为k&#xff0c;值的长度为v。 q ∈ 1 q , k ∈ 1 k …

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第54课-poplang语音编程控制机器人

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第54课-poplang语音编程控制机器人 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的…

SQL 对一个经常有数据更新和删除操作的表,怎样优化以减少磁盘空间的占用?

文章目录 一、定期清理不再需要的数据二、使用合适的数据类型三、压缩数据四、删除重复数据五、分区表六、索引优化七、碎片整理八、归档历史数据九、监控和评估 在数据库管理中&#xff0c;当面对一个经常进行数据更新和删除操作的表时&#xff0c;磁盘空间的有效利用是一个重…

Pogo-DroneCANPWM模块:可实现DroneCAN转PWM,DroneCAN转dshot,DroneCAN转bdshot

关键词&#xff1a;Ardupilot&#xff0c;Pixhawk&#xff0c;PWM&#xff0c;dshot&#xff0c;bdshot&#xff0c;DroneCANPWM&#xff0c;电调ESC&#xff0c;DroneCAN&#xff0c;UAVCAN&#xff0c;飞控&#xff0c;无人机&#xff0c;UAV Keywords&#xff1a;Ardupilot…

MSPM0G3507——OPENMV给M0传数据(用数据包)互相通信(以循迹为例)

OPENMV端代码 # main.py -- put your code here! import pyb, sensor, image, math, time from pyb import UART import ustruct from image import SEARCH_DS, SEARCH_EX import time import sensor, displayuart UART(3, 115200, bits8, parityNone, stop1, timeout_char10…

计算机网络性能指标概述:速率、带宽、时延等

在计算机网络中&#xff0c;性能指标是衡量网络效率和质量的重要参数。本文将综合三篇关于计算机网络性能指标的文章&#xff0c;详细介绍速率、带宽、吞吐量、时延、时延带宽积、往返时延&#xff08;RTT&#xff09; 和利用率的概念及其在网络中的应用。 1. 速率&#xff08;…

开源六轴协作机械臂myCobot280实现交互式乘法!让学习充满乐趣

本文经作者Fumitaka Kimizuka 授权我们翻译和转载。 原文链接&#xff1a;myCobotに「頷き」「首振り」「首傾げ」をしてもらう &#x1f916; - みかづきブログ・カスタム 引言 Fumitaka Kimizuka 创造了一个乘法表系统&#xff0c;帮助他的女儿享受学习乘法表的乐趣。她可以…

大语言模型基础

大语言基础 GPT : Improving Language Understanding by Generative Pre-Training 提出背景 从原始文本中有效学习的能力对于减轻自然语言处理中对监督学习的依赖至关重要。很多深度学习方法需要大量人工标注的数据&#xff0c;限制了它们在很多领域的应用&#xff0c;收集更…

cs231n作业2 双层神经网络

双层神经网络 我们选用ReLU函数和softmax函数&#xff1a; 步骤&#xff1a; 1、LOSS损失函数&#xff08;前向传播&#xff09;与梯度&#xff08;后向传播&#xff09;计算 Forward: 计算score&#xff0c;再根据score计算loss Backward&#xff1a;分别对W2、b2、W1、b1求…

multisim中关于74ls192n和DSWPK开关仿真图分析(减法计数器)

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

直播预告 | VMware大规模迁移实战,HyperMotion助力业务高效迁移

2006年核高基专项启动&#xff0c;2022年国家79号文件要求2027年央国企100%完成信创改造……国家一系列信创改造政策的推动&#xff0c;让服务器虚拟化软件巨头VMware在中国的市场份额迅速缩水。 加之VMware永久授权的取消和部分软件组件销售策略的变更&#xff0c;导致VMware…