
从C++11开始,语法里多了一个类型运算符decltype,它可以返回表达式的类型。在C++里有个typeid运算符,也能返回类型,但是decltype和typeid使用上并不太一样,typeid事实上是返回了type_info类型的一个说明,例如
以下所有代码均在VS2015中测试,其他编译器不知道对不对
struct A { int x; };
int main(int arg) {
const type_info &s = typeid(A);
cout << s.name() << endl;
}
以上代码输出
struct A
但是decltype是直接返回了测试表达式的类型,例如
int main(int arg) {
decltype(6) j = 2;
cout << typeid(j).name()<< endl;
cout << j << endl;
}
以上代码输出
int
2

decltype的基本使用
decltype这个东西是英文declare type缩写,就是声明一个类型的意思。其实,decltype有点像宏定义,但又不太一样,它和sizeof的使用方式一样,虽然看上去像是函数调用的方式,但都是属于解释时执行,也就是说在解释时,这个东西就已经有结果了。
关于decltype可以简单理解为,编译器会把decltype以及括号内的东西,在编译期间一起替换为一个类型,这个类型是括号内的表达式指定的,如下面的代码
int x = 0;
decltype(x) j = 1;
可以理解为在程序实际编译时,编译器会把decltype(x)直接替换成int,最终要编译的代码如下
int x = 0;
int j = 1;
关于decltype的使用,decltype括号内可以放表达式,值类型,但是不能放类型,例如
decltype(1) a = 1;
decltype(a+1) d = 2;
decltype(int) c=2
decltype(a->x) c = 1;
A * f =new A;
decltype(a) d = f;
decltype(A) e = f;
int abc();
decltype(abc()) c = 1;
可以看出,只要是可以确定类型的,decltype后面的括号内都能放,返回的类型就是括号内表达式的类型
不过,有一种返回类型可能和你预期不太一样,对比下列两组代码
int ddd = 1;
decltype(ddd) c = 1;
int ddd = 1;
decltype((ddd)) c = 1;
第二组代码decltype((ddd)),只比第一组代码给ddd多了一个括号,但第二组代码就是错误的。这就是涉及一个左右值的问题了
ddd 在第一组代码里 表示了int 类型,但在第二组内加了括号,他就变为了一个左值,就会返回一个引用,所以
decltype((ddd)) c = 1;
并非返回int,而是返回int的引用,int&
但是,也不能简单理解为就是加了括号就会变为左值。例如
int abc();
decltype((abc())) j = 0;
上面这个代码就是正确,因为abc是个函数,无论套多少层括号,最终就是返回int
同样,有些没有括号,也会返回是类型引用
int ddd = 1;
int fff;
int ccc;
decltype(ddd == 1 ? fff : ccc) c =1 ;
decltype((ddd == 1 ? fff : ccc)) c = 1;
以上也是错误的,因为C 是 int&
表达式
ddd == 1 ? fff : ccc
确实可以作为左值

在模板中使用
事实上,通过上面的代码可以看出来,如果就按上面的用法的话,好像这个东西也没有太大实际的意义,因为不管是函数,还是变量,你一定可以知道它的类型。
但是如果在模板中,就有用了,如下代码
template<typename T, typename D> auto abc(T a, D c) -> decltype(a > c ? a : c);
int main(int arg) {
cout << typeid(abc(1, 2)).name()<<endl;
cout << typeid(abc(1, 1.15)).name()<< endl;
return 1;
}
如果只有模板函数定义,返回是auto,还没有定义具体实现的时候,编译器没法推断返回类型.
但是加了decltype(a > c ? a : c),编译器就能推断类型了,上述代码输出
int
double

decltype和typeid
在上面就说过,decltype更像sizeof 的使用方式,它在程序的解释阶段就已经出现了结果,而typeid则不是,typeid是在运行时出的结果,也就是说,它实际上是一个函数调用,比如要调用typeid的name函数,可以看到他确实是调用了一个name函数  而decltype运行,可以看到,实际运行时就已经知道了x的类型 所以,他们功能上不太一样,decltype最终返回了一个真正的可以让编译器解释的类型,而typeid返回的是这个类型的说明。

|