1.在泛型编程中,可能需要通过参数的运算来得到返回值的类型。考虑下面这个场景:
template <typename R, typename T, typename U>
R add(T t, U u)
{
return t+u;
}
int a = 1; float b = 2.0;
auto c = add<decltype(a + b)>(a, b);
我们并不关心 a+b 的类型是什么,因此,只需要通过 decltype(a+b) 直接得到返回值类型即可。但是像上面这样使用十分不方便,因为外部其实并不知道参数之间应该如何运算,只有 add 函数才知道返回值应当如何推导。
2.那么,在 add 函数的定义上能不能直接通过 decltype 拿到返回值呢?
template <typename T, typename U>
decltype(t + u) add(T t, U u) // error: t、u尚未定义
{
return t + u;
}
当然,直接像上面这样写是编译不过的。因为 t、u 在参数列表中,而 C++ 的返回值是前置语法,在返回值定义的时候参数变量还不存在。
3.因此,在 C++11 中增加了返回类型后置(trailing-return-type,又称跟踪返回类型)语法,将 decltype 和 auto 结合起来完成返回值类型的推导。返回类型后置语法是通过 auto 和 decltype 结合起来使用的。上面的 add 函数,使用新的语法可以写成:
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u)
{
return t + u;
}
4.追踪返回类型的函数与普通函数最大区别在于返回类型后置。如下两种写法的示例:
// 普通函数声明
int func(char* a, int b);
// 追踪返回类型的函数声明
auto func(char* a, int b) -> int;
5.广泛应用在转发函数中。如下示例:
#include <iostream>
using namespace std;
double foo(int a)
{
return (double)a + 0.1;
}
int foo(double b)
{
return (int)b;
}
template <class T>
auto Forward(T t) -> decltype(foo(t))
{
return foo(t);
}
int main()
{
cout << Forward(2) << endl; // 2.1
cout << Forward(0.5) << endl; // 0
}