C++11之追踪返回类型

简介: C++11之追踪返回类型

追踪返回类型

追踪返回类型的引入

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


在函数模板中,函数的类型取决于参数的类型,那么当参数类型是动态时,返回类型也是动态的。

下面我以俩数相加函数为例:

template<typename T1, typename T2>
decltype(t1 + t2) Sum(T1& t1, T2& t2)
{
  return t1 + t2;
}


输入的类型不确定 返回的类型不确定

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

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

template<typename T1, typename T2>
void Sum(T1& t1, T2& t2, decltype(t1 + t2)& ret)
{
  ret = t1 + t2;
}


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

int main()
{
  int i = 9;
  double j = 3.3;
  double s = 0;
  Sum(i, j, s);
  cout << s << endl;
  return 0;
}


使用追踪返回类型的函数

上述的解决方案都并不是那么的完美,为此C++11引入了新语法 追踪返回类型,类似于lanbda的表达式中的返回类型的写法。

追踪返回类型:将函数的返回类型移到函数最后部分,格式:->返回类型 原本返回类型的位置将会由auto去占位。这样完美就可以让编译器来推导Sum函数模板的返回类型了。auto占位符 与

->return_type 就构成了追踪返回类型函数的俩个基本必备要素。


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

template<typename T1, typename T2>
auto Sum(T1& t1, T2& t2)->decltype(t1 + t2)
{
  return 0;
}


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

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

int TestFunction1(int i)
{
  return i * 2;
}
auto TestFunction2(int i)->int
{
  return i * 2;
}


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

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


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

class OuterType
{
public:
  struct InnerType
  {
    int i;
  };
  InnerType GetInner();
  InnerType it;
};
auto OuterType::GetInner()->/*OuterType::*/InnerType
{
  return it;
}

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


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

#include <iostream>
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;
}

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

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

#include <type_traits>
#include <iostream>
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;
}


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

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

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

#include <iostream>
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;
}


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

目录
相关文章
|
1月前
|
C++
C++ 数学函数、头文件及布尔类型详解
C++ 支持数学操作,如`max`和`min`函数找最大值和最小值,以及`&lt;cmath&gt;`库中的`sqrt`、`round`等数学函数。`bool`类型用于布尔逻辑,取值`true`(1)或`false`(0)。布尔表达式结合比较运算符常用于条件判断,例如在`if`语句中检查年龄是否达到投票年龄。在代码示例中,`isCodingFun`和`isFishTasty`变量分别输出1和0。
124 1
|
2月前
|
算法 编译器 C++
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits 判断 Lambda表达式类型?
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits 判断 Lambda表达式类型?
45 4
|
2月前
|
算法 编译器 C语言
【C++ 迭代器的空类类型 】深入理解C++迭代器类别与空类标签的奥秘
【C++ 迭代器的空类类型 】深入理解C++迭代器类别与空类标签的奥秘
35 0
|
2月前
|
存储 安全 C++
C++ 用户输入与数据类型详解:建立基本计算器及变量类型
了解C++的用户输入和数据类型。使用`cin`从键盘读取数据,如在简单计算器示例中获取两个数字并求和。C++的数据类型包括:`int`(整数)、`float`(浮点数,约6-7位小数)、`double`(更精确的浮点数,约15位小数)、`bool`(布尔值,true或false)、`char`(单个字符)和`string`(文本字符串)。每种类型都有特定的存储大小和用途。在处理浮点数时,`double`通常更安全。字符串需要包含`&lt;string&gt;`库。更多内容可关注微信公众号`Let us Coding`获取。
40 0
|
2月前
|
存储 安全 算法
【C/C++ 数据发送结构设计】C++中的高效数据发送:多态、类型擦除与更多解决方案
【C/C++ 数据发送结构设计】C++中的高效数据发送:多态、类型擦除与更多解决方案
79 0
|
2月前
|
存储 算法 编译器
【C++ 函数尾部返回】C++中的尾返回类型:探究auto func() -> ReturnType的魔力
【C++ 函数尾部返回】C++中的尾返回类型:探究auto func() -> ReturnType的魔力
64 1
|
2月前
|
算法 编译器 数据库
【C++ 泛型编程 高级篇】使用SFINAE和if constexpr灵活处理类型进行条件编译
【C++ 泛型编程 高级篇】使用SFINAE和if constexpr灵活处理类型进行条件编译
250 0
|
2月前
|
设计模式 程序员 C++
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
270 2
|
2月前
|
安全 程序员 编译器
【C/C++ 泛型编程 进阶篇 Type traits 】C++类型特征探究:编译时类型判断的艺术
【C/C++ 泛型编程 进阶篇 Type traits 】C++类型特征探究:编译时类型判断的艺术
185 1
|
2月前
|
算法 程序员 C++
【C/C++ 泛型编程 应用篇】C++ 对多参数的参数包的 参数类型提取 应用
【C/C++ 泛型编程 应用篇】C++ 对多参数的参数包的 参数类型提取 应用
44 5