C++源码分析完美转发

news/2025/2/22 15:41:06/

C++源码分析完美转发

  • 完美转发作用:
    • 可以保持实参数据在函数中的左值或者右值类型。

不使用完美转发的后果

  • #include<iostream>
    using namespace std;// 容器里面元素的类型
    class A
    {
    public:A() {}// 带左值引用参数的赋值函数A& operator=(const A& src){cout << "operator=&" << endl;return *this;}// 带右值引用参数的赋值函数A& operator=(A&& src){cout << "operator=(A&&)" << endl;return *this;}
    };
    // 容器的类型
    template<typename _Ty>
    class Vector
    {
    public:// 引用左值的push_back函数void push_back(const _Ty& val){mvec[mcur++] = val;}// 引用右值的push_back函数void push_back(_Ty&& val){// 这里传递val时,要用move转换成右值引用类型,mvec[mcur++] = val;}
    private:enum { VEC_SIZE = 10 };_Ty mvec[VEC_SIZE];int mcur;
    };int main()
    {Vector<A> vec;A a;vec.push_back(a); // 调用A的左值引用的赋值函数vec.push_back(A()); // 理应调用A的右值引用参数的赋值函数,却调用了左值引用的赋值函数return 0;
    }
    

  • 可见,不使用完美转发,vec.push_back(A()); 理应调用A的右值引用参数的赋值函数,却调用了左值引用的赋值函数

    • image-20230519134624798
  • 原因:

    • 因为当传递右值给 push_back(_Ty&& val) 函数时
    • 由于 val右值引用的形参,它在函数内部被解释为左值引用,因此在函数体内部处理时,它仍然被视为左值。
  • 所以避免我们传递的右值引用 失去右值的效果,我们引入了 完美转发

引入完美转发

  • 源码:

    • template<class _Ty>_NODISCARD constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept{	// forward an lvalue as either an lvalue or an rvaluereturn (static_cast<_Ty&&>(_Arg));}template<class _Ty>_NODISCARD constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept{	// forward an rvalue as an rvaluestatic_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");return (static_cast<_Ty&&>(_Arg));}
      
  • 源码实现了两个版本的forward重载函数

    • 左值引用版本的

      • 调用场景

        • 不管传入的是左值右值,形参val都是左值,所以调用的都是forward的左值引用版本

        • 	template<class _Ty>_NODISCARD constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept{	// forward an lvalue as either an lvalue or an rvaluecout << "remove_reference_t<_Ty>& _Arg" << endl;return (static_cast<_Ty&&>(_Arg));}
          
          • 如果实参类型是int& + && -> **int&**就保持了实参的左值引用类型
          • 如果实参类型是int&& + && -> **int&&**就保持了实参的右值引用类型。
        • image-20230519135652756

    • 右值引用:

      • 只有传入的参数是 右值时,才会调用

        • template<class _Ty>_NODISCARD constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept{	// forward an rvalue as an rvaluestatic_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");return (static_cast<_Ty&&>(_Arg));}
          
        • image-20230519135747009

总结

  • 利用完美转发,我们可以可以保持实参数据在函数中的左值或者右值类型,从而达到我们想要的效果

http://www.ppmy.cn/news/73708.html

相关文章

软件之禅(一)Hello,World!

黄国强 2023/5/19 近半年比较空&#xff0c;思考多了一点。 之前工作比较忙&#xff0c;而且工作中遇到的问题都能用自己掌握的方法应付。这样思想就懈怠了。 个人打算写一个系列文章&#xff0c;试图用第一性原理来把我自己掌握的知识梳理一遍&#xff0c;看看是否能更深入的…

计算机视觉的应用6-利用VGG模型做毕加索风格图像迁移

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用5-利用VGG模型做毕加索风格图像迁移&#xff0c;本文将利用VGG模型实现毕加索风格图像迁移的方法。首先&#xff0c;我们将简要说明图像风格迁移的原理&#xff0c;然后使用PyTorch框架&#xff0c…

Redis哨兵集群搭建及其原理

Redis哨兵集群搭建及其原理 1.Redis哨兵1.1.哨兵原理1.1.1.集群结构和作用1.1.2.集群监控原理1.1.3.集群故障恢复原理1.1.4.小结 2.搭建哨兵集群2.1.集群结构2.2.准备实例和配置2.3.启动2.4.测试 3.RedisTemplate3.1.引入依赖3.2.配置Redis地址3.3.配置读写分离 1.Redis哨兵 R…

数据库相关知识

一.1 数据库 与Sybase不同&#xff0c;一个用户就对应于一个数据库。 create user CBMAIN identified by "sunline" default tablespace CBMAIN_DATA  -- 表空间 temporary tablespace CBMAIN_TEMP; -- 临时表空间 一.2 表空间 表空间由一个或多个物理文件组成&…

【新星计划】数据库 排名函数 初识

数据库 排名函数 初识 查询排序初识排名函数row_number()rank()dense_rank()ntile()percent_rank() 开窗函数为聚合函数使用开窗函数 小结 查询排序 在日常工作中&#xff0c;我们对所有需要的数据都会进行一个排序操作&#xff0c;以获得我们最需要的数据。 排序指令 order …

联想首次展示全栈算力方案服务,品牌换新亮相

1、联想算力&#xff0c;第一次真正被所有人感知。 2、基于软硬服一体化的优势&#xff0c;联想打造了丰富多样的四维算力服务&#xff0c;即融合化、场景化、订阅化、绿色化&#xff0c;可以满足不同企业、不同行业的定制化需求。 5月20日&#xff0c;主题为“联想方案服务&am…

就业内推 | 应届生专场,有华为、思科认证优先,六险一金

01 金科 &#x1f537;招聘岗位&#xff1a;网络工程师 &#x1f537;职责描述&#xff1a; 1、为银行、企业客户提供技术服务&#xff08;包括驻场支持和现场技术支持&#xff09;&#xff1b; 2、驻客户现场配合客户完成思科、华三、华为主流网络设备的配置、管理&#xff1…

机器学习 | MATLAB实现Bayes贝叶斯优化机器学习模型答疑

机器学习 | MATLAB实现Bayes贝叶斯优化机器学习模型答疑 目录 机器学习 | MATLAB实现Bayes贝叶斯优化机器学习模型答疑问题汇总问题1答疑问题2答疑问题3答疑问题汇总 问题1:想问一下贝叶斯优化最小目标值,是什么值? 问题2:想问一下贝叶斯优化目标函数? 问题3:贝叶斯优化的…