源从何来
很长时间以来我们都希望有这么一个功能:给定一个对象,通过某个函数或者关键字,获得它的类型。c++有typeid的实现,也就是返回一个对象的typeid字符串,但是这个字符串不能用来声明一个新变量。因此c++11就出现了decltype这个关键字。
三大作用
声明返回类型
1
2template<typename T1, typename T2>
decltype(x + y) add(T1 x, T2 y);还有另外一种写法:
1
2template<typename T1, typename T2>
auto add(T1 x, T2 y) -> decltype(x + y);//和lambda有点像?在上面这个函数里,有两个模板参数,变量x和y对operator + 进行操作符重载之后,我们不知道函数的返回类型是什么,这个时候我们就可以用decltype来做。
元编程
在模板函数或者模板类里面,可以灵活使用decltype来获得模板类型定义新变量。1
2
3
4
5
6
7
8
9
10template<typename T>
void foo(T obj){
map<int, string> coll;
//通过对象名拿到类型
decltype(coll)::value_type elem;
//得到模板参数对象的迭代器名
typedef typename decltype(obj)::iterator iterType;
//定义迭代器
iterType iter;
}传递lambda表达式的类型
使用decltype和lambda可以起到仿函数的作用。1
2
3
4auto cmp = [](const Foo& f1, const Foo& f2){
return f1.data() > f2.data();
};
std::set<Foo,decltype(cmp)> coll(cmp);
和auto的区别
- auto类型说明符用编译器计算变量的初始值来推断其类型,而decltype虽然也让编译器分析表达式并得到它的类型,但是不实际计算表达式的值。
- 编译器推断出来的auto类型有时候和初始值的类型并不完全一致,编译器会适当的改变结果类型使其更符合初始化规则,例如,auto一般会忽略掉顶层const,而把底层const保留下来,与之相反,decltype会保留变量的顶层const。
- decltype的结果类型与表达形式密切相关。有一种情况需要特别注意:对于decltype 所用表达式来说,如果变量名加上一对括号,则得到的类型与不加上括号的时候可能不同。如果decltype使用的是一个不加括号的变量,那么得到的结果就是这个变量的类型。但是如果给这个变量加上一个或多层括号,那么编译器会把这个变量当作一个表达式看待,变量是一个可以作为左值的特殊表达式,所以这样的decltype就会返回引用类型。