码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • C++11之追踪返回类型


    系列文章

    C++11之正则表达式(regex_match、regex_search、regex_replace)

    C++11之线程库(Thread、Mutex、atomic、lock_guard、同步)

    C++11之智能指针(unique_ptr、shared_ptr、weak_ptr、auto_ptr)浅谈内存管理

    C++11之强制类型转换(static_cast,const_cast,dynamic_cast,reinterpret_cast)

    C++11之Lanbda表达式(匿名函数)

    C++11之右值引用:移动语义和完美转发(带你了解移动构造函数、纯右值、将亡值、右值引用、std::move、forward等新概念)

    C++11之委派构造函数

    C++11之内联名字空间(inline namespace)和ADL特性(Argument-Dependent name Lookup)

    C++11之模板的别名

    C++11之一般化的SFINAE规则

    C++11之auto类型推导

    C++11之decltype类型推导(使用场景、推导四规则、cv限定符)


    目录

    • 系列文章
    • 追踪返回类型
      • 追踪返回类型的引入
      • 使用追踪返回类型的函数
      • 常规/普通函数中也可以使用追踪返回类型
      • 返回类型如果和函数的作用域相同或者被包含时则返回类型处可以省略作用域
      • 在处理函数简化问题上,追踪返回类型也是一把好手
      • 参数与返回值类型不同时的转发


    追踪返回类型

    追踪返回类型的引入

    前面我们讲了auto和decltype在泛式编程中的作用,今天我们在学一个能够让auto和decltype在泛式编程中更加强大的----追踪返回类型

    在函数模板中,函数的类型取决于参数的类型,那么当参数类型是动态时,返回类型也是动态的。
    下面我以俩数相加函数为例:

    template<typename T1, typename T2>
    decltype(t1 + t2) Sum(T1& t1, T2& t2)
    {
    	return t1 + t2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输入的类型不确定 返回的类型不确定
    就会写出下面这种返回类型。由于C++编译器是从左往右顺序读入的,按照变量需要先声明后使用的规则,所以这种写法注定是不会编译器允许的。

    在这里插入图片描述

    为了满足C/C++编译器的规则,所以我们可以将计算得到的结果从返回值的形式转为出参。

    template<typename T1, typename T2>
    void Sum(T1& t1, T2& t2, decltype(t1 + t2)& ret)
    {
    	ret = t1 + t2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样的写法的确满足了编译器的规则,但是在使用方上并没有提高便捷性,因为这种的函数模板需要在使用时就需要确定出参类型,因为要先定义。

    int main()
    {
    	int i = 9;
    	double j = 3.3;
    
    	double s = 0;
    	Sum(i, j, s);
    	cout << s << endl;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    使用追踪返回类型的函数

    上述的解决方案都并不是那么的完美,为此C++11引入了新语法 追踪返回类型,类似于lanbda的表达式中的返回类型的写法。
    追踪返回类型:将函数的返回类型移到函数最后部分,格式:->返回类型 原本返回类型的位置将会由auto去占位。这样完美就可以让编译器来推导Sum函数模板的返回类型了。auto占位符 与
    ->return_type 就构成了追踪返回类型函数的俩个基本必备要素。

    下面就是使用追踪返回类型的方法实现的俩数相加的函数

    template<typename T1, typename T2>
    auto Sum(T1& t1, T2& t2)->decltype(t1 + t2)
    {
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    常规/普通函数中也可以使用追踪返回类型

    这种追踪返回类型不仅仅局限于上述的场景,在常规/普通函数中也可以使用。

    int TestFunction1(int i)
    {
    	return i * 2;
    }
    
    auto TestFunction2(int i)->int
    {
    	return i * 2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    返回类型如果和函数的作用域相同或者被包含时则返回类型处可以省略作用域

    令人糟糕的是,上述的例子在写法上复杂了,而且易读性也降低了。但它也有好处,返回类型如果和函数的作用域相同或者被包含时则返回类型处可以省略作用域。

    下面我创建了一个OuterType类,还有一个成员函数,其中这个函数返回类型的作用域也是在OuterType类内,所以返回类型的作用域就可以省略掉。

    class OuterType
    {
    public:
    	struct InnerType
    	{
    		int i;
    	};
    
    	InnerType GetInner();
    	InnerType it;
    };
    
    auto OuterType::GetInner()->/*OuterType::*/InnerType
    {
    	return it;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    C++11引追踪返回类型后,对于模板编程中的类型推导也提高了一个台阶,让泛式编程更加强大 直观的看代码,有种python的感觉,模板函数中没有一个具体的类型。而对于模板的设计者提供了极高的便捷性,编写上也极大的简化了代码的体积。

    下面实现了俩数相加、俩数相乘的函数,均采用追踪返回类型的方式。那么在调用者使用的过程中是非常的便捷。

    #include 
    
    using namespace std;
    
    template<typename T1, typename T2>
    auto Sum(const T1& t1, const T2& t2)->decltype(t1 + t2)
    {
    	return t1 + t2;
    }
    
    template<typename T1, typename T2>
    auto Mul(const T1& t1, const T2& t2)->decltype(t1 * t2)
    {
    	return t1 * t2;
    }
    
    int main()
    {
    	auto a = 3;
    	auto b = 4LL;
    	auto pi = 3.14;
    
    	auto c = Mul(Sum(a, b), pi);
    
    	cout << c << endl;
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在处理函数简化问题上,追踪返回类型也是一把好手

    下面定义了令人头疼的pf函数,我们可以使用追踪返回类型很容易的将其简化。而且我们还可以通过is_same模板类来测试俩个函数是否相同。

    #include 
    #include 
    using namespace std;
    
    
    int (*(*pf())())()
    {
    	return nullptr;
    }
    
    /*
     * auto (*)() -> int(*)()  一个返回函数指针的函数 该函数没有参数,返回值类型为int  设这个函数为x
     * auto pf1() ->auto (*)() -> int(*)()  一个返回a函数指针的函数
     */
    auto pf1() ->auto(*)()->int(*)()
    {
    	return nullptr;
    }
    
    int main()
    {
    	cout << boolalpha << is_same<decltype(pf), decltype(pf1)>::value << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    参数与返回值类型不同时的转发

    追踪返回类型的强大远不止于此,在模板函数中加入追踪返回类型可以实现参数与返回值类型不同时的转发。

    在下面的代码中,我们实现了int转double和double转int的同名函数,还实现了一个Forward转发函数,其返回类型是通过fool(参数)的方式进行确定的。这样就可以根据输入的类型动态的变化返回的类型。

    #include 
    
    using namespace std;
    
    double foo(int a)
    {
    	return static_cast<double>(a) + 0.1;
    }
    
    int foo(double d)
    {
    	return static_cast<int>(d);
    }
    
    template<class T>
    auto Forward(T t)->decltype(foo(t))
    {
    	return foo(t);
    }
    
    int main()
    {
    	cout << Forward(1.2) << endl;
    	cout << Forward(2) << endl;
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    还可以广泛应用于函数指针、普通函数、函数应用等等中。没有返回类型的函数也可以被声明为追踪返回类型,只需要将最后的return_type写为void即可。

  • 相关阅读:
    代码规范问题,“static“ base class members should not be accessed via derived types
    说实话ThreadLocal真不是啥高级的东西
    记一次 OSS 大批量文件下载的实现 → bat脚本不好玩!
    CentOS7上从0开始搭建Zookeeper集群
    LeetCode 134.加油站
    stm32的时钟、中断的配置(针对寄存器),一些基础知识
    leetcode 367 有效的完全平方数
    从理解路由到实现一套Router(路由)
    Rust解决Bug错误“error: future cannot be sent between threads safely”
    2022年这一批陕西省工程职称评审难度调整了
  • 原文地址:https://blog.csdn.net/qq_45254369/article/details/127452583
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号