decltype in c++11

decltype

decltype是c++11引入的类型推导标记符,与auto类似。基本语法比较简单,就是给一个表达式,返回表达式的类型:

1
decltype ( expression )

这里只会查询表达式的返回类型,并不会对表达式进行求值。

decltype的判断规则是比较复杂的,主要分为以下几类:

  • 如果参数是无括号的标识表达式或无括号的类成员访问表达式,decltype会返回以该表达式命名的实体类型。但如果参数是一个重载函数,则会编译错误;
  • 若参数是其他类型为 T 的任何表达式
    • 表达式的值类型为临时值/亡值,则会返回T&&;
    • 表达式的值类型为左值,则会参会T&;
    • 纯右值,则会返回T;

需要注意的是,如果对象的名字带有括号,则它被当做通常的左值表达式,从而 decltype(x) 和 decltype((x)) 通常是不同的类型。

举个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct A { double x; };
const A* a;
int i=10;

decltype(a->x) y; // y 的类型是 double(其声明类型)
decltype((a->x)) z = y; // z 的类型是 const double&(被当作左值表达式)
decltype((i))b = i; // b 的类型是 int&

// 或者用在无名函数的类型推导上
auto f = [](int a, int b) -> int
{
return a * b;
};

decltype(f) g = f;
i = f(2, 2);
j = g(3, 3);

在日常编程中,用到decltype的情况还是比较少的,我们一般用在模版中,结合auto和尾返回类型,我们可以写出语言级别支持的简洁代码:

1
2
template<typename T, typename U>
auto foo(T t, U u) -> decltype(t + u) { return t + u; }

另外,要判断是否为左值,可以考虑使用c++11标准库提供的模版类来做检查:

1
is_lvalue_reference<decltype(++i)>::value;