返回值类型后置语法,是为了解决函数返回值类型依赖于参数而导致难以确定返回值类型的问题。有了这种语法以后,对返回值类型的推导就可以用清晰的方式(直接通过参数做运算)描述出来,而不需要像 C++98/03 那样使用晦涩难懂的写法。
在泛型编程中,我们可能会遇到,通过参数运算得到的返回值如下面的例子。
在此之前,我当你了解了auto与decltype,不了解可以看看我以前的博客。
例子如下:
#include
#include
using namespace std;
template <typename R, typename T, typename U>
R add(T t, U u)
{
return t + u;
}
int main()
{
char a = 'a';
string b = "32";
auto c = add<decltype(a + b)>(a, b);
cout << "auto c: " << c << endl;
system("pause");
}
好像这样也行, decltype(a+b) 直接得到返回值类型。但是函数外部,不应该知道函数的内部运算。
那根据之前所学,你可能想到用decltype得到返回值类型,并且写下下面一段
#include
template <typename T, typename U>
decltype(t + u) add(T t, U u) //前面的t、u未定义标识符
{
return t + u;
}
但是编译器报错了,出现了未定义标识符t和u。出现这样的问题是因为 t、u 在参数列表中,而 C++ 的返回值是前置语法,在返回值定义的时候参数变量还不存在。
在C++1.0(也就是C++98)可以这样写(可行方法)
template <typename T, typename U>
decltype((*(T*)0) + (*(U*)0)) add(T t, U u)
{
return t + u;
}
在C++2.0(C++11)新增加了返回值类型后置(又称跟踪返回类型)的语法,将 decltype 和 auto 结合起来完成返回值类型的推导
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u)
{
return t + u;
}
这个写法比较与C++1.0的看起来简洁,增加了阅读性。当然啦,有些复杂的例子C++1.0是做不到的。
#include
using namespace std;
int& foo(int& i)
{
return i;
}
float foo(float& f)
{
return f;
}
template <typename T>
auto func(T& val) -> decltype(foo(val))
{
return foo(val);
}
using namespace std;
int main()
{
float f = 3.14;
int i = 3;
auto a = func<int>(i);
cout << a << endl; //输出3
auto b = func<float>(f);
cout << b << endl;//输出3.14
return 0;
}