「这是我参与11月更文挑战的第 9 天,活动详情查看:2021最后一次更文挑战」。
参加该活动的第 20 篇文章
预备知识
decltype
其作用是用于查询表达式的数据类型,例如:
/// @note 用于测试的类型
const int &&foo();
const int bar();
int i;
struct A
{
double x;
};
const A *a = new A();
// --------------------------------------------
decltype(foo()) x1; ///< 推断类型为 const int&&
decltype(bar()) x2; ///< 推断类型为 int
decltype(i) x3; ///< 推断类型为 int
decltype(a->x) x4; ///< 推断类型为 double
decltype((a->x)) x5; ///< 推断类型为 const double& (注意,加了个括号推断出的类型就不同了)
通过上面的例子我们可以看到 decltype
可以根据一个左值或者右值来推断出其类型。
返回值难以推断的问题
有时候在泛型编程时,有些函数的返回类型难以确定。例如,下面这个返回值我们难以确定:
template <typename U, typename T>
R Add(U u, T t)
{
auto val = u + t;
return val;
}
C++11 如何解决上面的问题
在 C++11 可以通过返回值后置来解决这个问题,即需要利用 auto
和 decltype
。首先使用 auto
作为一个返回值占位符【auto 有一个特性:返回值占位。使用 auto 后,将由编译器自动进行确定】,返回值类型在稍后通过 decltype
推断出来。例如,我们可以写成下面这种形式
template <typename U, typename T>
auto Add(U u, T t) -> decltype(u + t) ///< 不要和 lambda 表达式混淆了
{
auto val = u + t;
return val;
}
至于为什么需要将返回值类型后置,这里简单说明一下。如果没有后置,则函数声明为
decltype(u+t) Add(U u,T t)
,但此时模板参数t
和u
还未声明,编译无法通过。另外,如果非要使用返回值类型前置的形式,也可以将函数声明为decltype((*(U*)0)+(*(T *)0)) Add(U u, T t)
,但这种形式比较晦涩难懂,因此不推荐采用。
auto
和 decltype
在很多方面简化了我们的代码,解决了有时因为类型难以推断或者难以书写的烦恼 !