C++11: 返回值类型后置语法
今天在看 cpprestsdk 的源码的时候发现一个方法的定义是这样的:
template<typename _Ty>
__declspec(noinline) auto create_task(_Ty _Param, task_options _TaskOptions = task_options())
-> task<typename details::_TaskTypeFromParam<_Ty>::_Type>
{...}
语法为:
auto fun_name(argument-declarations...) -> return_type{}
我们知道 C++11 的 lambda 表达式可以使用 `->` 指定返回参数的类型, 没想到声明方法也可以这么用。这种写法和传统的方法有什么区别呢?
在泛型编程中,一个常见的例子如下:
template <typename T>
T add(T a, T b) {
return a + b;
}
如果 `a` 和 `b` 的类型不同,需要怎么写呢?
template<typename R, typename T1, typename T2>
R add(T1 a, T2 b) {
return a + b;
}
auto ret_val = add<float>(1.0, 2);
auto ret_val1 = add<decltype(1.0 + 2)>(1.0, 2);
我们在调用此方法时必须显示指定 `R` 的类型, 或者使用 `decltype` 运算符推导返回值类型。如果让调用的方式简单点呢?把返回值类型放到定义中去, 像这样:
template <typename T1, typename T2>
decltype(a + b) add(T1 a, T2 b) {
return a + b;
}
然而这么写是编译不过的。因为 `a`, `b` 在参数列表中,编译器解析返回值的时候,它们还没有定义。那么我们可以这样写:
template <typename T1, typename T2>
decltype((*(T1*)0) + (*(T2*)0)) add(T1 a, T2 b) {
return a + b;
}
不过这太晦涩了。
C++ 11 允许将返回值类型后置,前面使用 auto 占位:
template <typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {
return a + b;
}
auto ret_val = add(1.0, 2); // 返回类型为 double
auto ret_val1 = add(1, 2); // 返回类型为 int
后置返回值类型使得编码更方便优雅。而下面这种用法 ,可以完成 C++98/03 无法完成的任务。
int foo(int i) { return i; }
float foo(float f) { return f; }
char foo(char c) { return c; }
template <typename T>
auto fun(T a) -> decltype(foo(a)) {
//...
return foo(a);
}
总之: 返回值类型后置可以解决返回值类型需要依赖参数类型而无法确定的问题