C++11常规特性之auto和decltype

在C++11之前,auto用来声明对象的存储期,修饰普通局部栈变量,是自动存储,这种对象会自动创建和销毁。在C++11新特性中,用来实现类型的推判。auto现在成了一个类型的占位符,通知编译器去根据初始化代码推断所声明变量的真实类型。特别是在循环遍历容器的时候,auto会显得很有用。

1
2
3
4
5
6
7
8
9
auto i = 42;
auto a = 3.14;
auto p = new Ptr();
auto i=0,&r=i;
auto a=r;//a为int,因为r是i的别名,i为int。
vector<int> v;
auto b = v.begin();
std::map<std::string, std::vector<int>> map;
for(auto it = begin(map); it != end(map); ++it) {};

需要注意的是,auto不能用来声明函数的返回值。但如果函数有一个尾随的返回类型时,auto是可以出现在函数声明中返回值位置。这种情况下,auto并不是告诉编译器去推断返回类型,而是指引编译器去函数的末端寻找返回值类型。在下面这个例子中,函数的返回值类型就是operator+操作符作用在T1、T2类型变量上的返回值类型。

1
2
3
4
5
6
template <typename T1, typename T2>
auto compose(T1 t1, T2 t2) -> decltype(t1 + t2)
{
return t1+t2;
}
auto v = compose(2, 3.14); // v's type is double

使用auto时,你只是需要一个变量的类型初始化。如果你需要一个类型不是一个变量,那么你需要用到decltype,例如返回类型。decltype是根据变量推导获取出变量的类型。目的是选择并返回操作数的数据类型,重要的是,在此过程中编译器分析表达式并得到它的类型,却不实际计算表达式的值。

1
2
3
4
5
6
7
8
9
decltype(f()) sum=x;  //sum的类型就是f返回值的类型, 但是这里不执行函数f()
auto x= 12;
auto y = 13;
typedef decltype(x*y) Type;
decltype(x*y) xy; //xy的类型为int
//decltype声明函数指针的时,关键是要记住decltype返回的是一个函数的类型的,因此要加上*声明符才能构成完整的函数指针的类型
int f(int a, int b){return a+b;};
decltype(f)* k = f; //直接decltype(f) k = f 是不可以的
k(1, 2);

如果decltype使用表达式的结果类型可以作为一条赋值语句的左值,那么decltype返回一个引用类型,例如解引用操作和变量加括号的类型。

1
2
3
4
5
6
int k=9;
decltype(*p) c=k; //c为int&,必须初始化
decltype((i)) d = k; //d为int&,必须初始化
decltype(++i) e = k //e为int&, 必须初始化
decltype(i++) f; //f 为int类型
tecltype(f=k) g //g为int&类型,必须初始化

auto和decltype的区别

const和引用

auto和const的推断与decltype不一样,对于auto,变量顶层的const会被忽略,只保留底层的const

1
2
3
4
5
6
7
8
onst int ci=i,&cr=i;
auto a=ci; //a为int(忽略顶层const)
auto b=cr; //b为int(忽略顶层const,cr是引用)
auto c=&i; //c为int *
auto d=&ci; //d是pointer to const int(&ci为底层const)
//要声明顶层const,前面要加上const关键字;要声明引用要加上&标识符
const auto f=ci; //ci的推演类型是int,f是const int
auto &g=ci;// g是一个绑定到ci的引用

对于decltype,其对const和应用的处理如下

1
2
3
4
5
6
const int ci=0;
decltype(ci) x=0; //x的类型是const int
int i=42,*p=&i,&r=i;
decltype(r+0) b; //b为int
const int &cj=ci;
decltype(cj) y=x; //y的类型是const int&,y绑定到x上