C++11 追踪返回类型
【1】追踪返回类型的引入
为什么要引入追踪返回类型?
在C++98中,如果一个函数模板的返回类型依赖于实际入口参数类型,那么该返回类型在模板实例化之前可能都无法确定。
还记得Sum模板函数吗?请看如下演化过程:
1 #include <iostream> 2 using namespace std; 3 4 // 演化1 (限制了Sum的使用范围) 5 template <typename T1, typename T2> 6 double Sum(T1& t1, T2& t2) 7 { 8 auto s = t1 + t2; 9 return s; 10 } 11 12 // 演化2 (改变了Sum的使用方式,不可以完全接受) 13 template <typename T1, typename T2> 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 <typename T1, typename T2> 22 decltype(t1 + t2) Sum(T1& t1, T2& t2) 23 { 24 return (t1 + t2); 25 } 26 #endif 27 28 29 // 演化4 (即追踪返回类型) 30 template <typename T1, typename T2> 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 <type_traits> 2 #include <iostream> 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<decltype(pf), decltype(pf1)>::value << endl; // 1 24 }
(4)广泛应用在转发函数中。如下示例:
1 #include <iostream> 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.
顺序 选择 循环 总结