C++11 追踪返回类型

【1】追踪返回类型的引入

为什么要引入追踪返回类型?

在C++98中,如果一个函数模板的返回类型依赖于实际入口参数类型,那么该返回类型在模板实例化之前可能都无法确定。

还记得Sum模板函数吗?请看如下演化过程:

 1 #include 
 2 using namespace std;
 3 
 4 // 演化1 (限制了Sum的使用范围)
 5 template 
 6 double Sum(T1& t1, T2& t2)
 7 {
 8     auto s = t1 + t2;
 9     return s;
10 }
11 
12 // 演化2 (改变了Sum的使用方式,不可以完全接受)
13 template 
14 void Sum(T1& t1, T2& t2, decltype(t1 + t2)& s)
15 {
16     s = t1 + t2;
17 }
18 
19 // 演化3 (编译失败,思考为什么?)
20 #if 0
21 template 
22 decltype(t1 + t2) Sum(T1& t1, T2& t2)
23 {
24     return (t1 + t2);
25 }
26 #endif
27 
28 
29 // 演化4 (即追踪返回类型)
30 template 
31  auto Sum(T1& t1, T2& t2) -> decltype(t1 + t2)
32 {
33     return (t1 + t2);
34 }
35 
36  int main()
37  {}

如上演化4 的写法:

将函数的返回值移至参数声明之后,复合符号->decltype(t1 + t2)被称为追踪返回类型,而原本函数返回值的位置由auto关键字占据。

如此这样,就可以由编译器来推导Sum函数模板的返回类型。

auto占位符和->return_type也就是构成追踪返回类型函数的两个基本元素。

【2】使用追踪返回类型的函数

(1)追踪返回类型的函数与普通函数的区别:

最大区别在于返回类型后置。如下两种写法的示例:

1  // 普通函数声明
2  int func(char* a, int b);
3 
4  // 追踪返回类型的函数声明
5  auto func(char* a, int b) -> int;

除过上节中提到使模板中的一些类型推导成为一种可能而外,其他使用:

(2)追踪返回类型声明的函数也会带给大家一些喜出望外的效果:如下示例:

 1 class OuterType
 2  {
 3      struct InnerType { int i; };
 4      InnerType GetInner();
 5      InnerType it;
 6  };
 7 
 8  // 可以不写OuterType::InnerType
 9  auto OuterType::GetInner()->InnerType
10  {
11      return it;
12  }

(3)简化函数的定义。常见于函数指针中,如下示例:

 1 #include 
 2 #include 
 3 using namespace std;
 4 
 5  // 有时候,你会发现这是面试题
 6  int (*(*pf()) ()) ()
 7  {
 8      return nullptr;
 9  }
10 
11  // 一个返回函数指针的函数(假设为func函数)
12  // auto (*)()->int(*)();
13  // 一个返回func函数的指针的函数
14  // auto pf1()->auto (*)() -> int(*)();
15 
16  auto pf1() -> auto(*)() -> int (*)()
17  {
18      return nullptr;
19  }
20 
21  int main()
22  {
23      cout << is_same::value << endl;  // 1
24  }

(4)广泛应用在转发函数中。如下示例:

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

 

good good study, day day up.

顺序 选择 循环 总结

你可能感兴趣的:(C++11 追踪返回类型)