C++11新标准中引入了auto和decltype这两种类型说明符,它们的共同点在于能够让编译器替我们分析表达式所属的类型,但是它们之间也存在一定的差异。下面就让我们来理解一下这两个类型说明符的不同。
auto
auto是让编译器通过初始值来推算变量的类型,故auto定义的变量必须有初始值。
auto n1 = 2; //n1是一个整数
auto n2 = 'a'; //n2是字符型
auto n3 = n1 + n2; //n2隐式转化为int型,故n3是int型
auto *n4 = &n3; //n4是一个整形指针
auto和复合类型、常量、指针
首先需要了解什仫是顶层const和底层const,对于指针来说:
顶层const表名指针本身是个常量;
底层const表名指针所指的对象是个常量;
const int i = 10; //i是整形常量
const int *p1 = &i; //p1是指向常量的指针,具有底层const属性
//int * const p2 = &i; //错误,&i的类型是const int *
const int * const p3 = &i;//p3为指向常量的常量指针,具有顶层const属性和底层const属性
auto p4 = p1; //保留底层const,p4的类型为const int *
auto p5 = p3; //保留底层const,忽略顶层const,p5的类型为const int *
auto p6 = &i; //保留底层const,p6的类型为const int *
对于auto保留底层const的性质,大家应该能很好的理解。
//auto会忽略顶层const,但会保留底层const
int i = 0, &r = i;
auto a = r; //a是一个整数
const int ci = i, &cr = ci;
auto b = ci; //b是一个整数
auto c = cr; //c是一个整数(cr是ci的别名,ci本身就是一个顶层const)
auto d = &i; //d是一个整形指针
auto e = &ci; //e是一个指向整数常量的指针(对常量对象取地址是一种底层const)
//如果希望推断出来的auto是一个顶层const,需要明确指出
const auto f = ci; //f是const int
//设置一个类型为auto的引用时,初始值中的顶层常量属性依然保留
auto k = ci, &l = i;
auto &m = ci, *p = &ci; //m是对整形常量的引用,p是指向整形常量的指针
const auto &n = i, *p2 = &ci; //&ci的类型是const int
decltype
如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。和auto不同的是,decltype是完全对应表达式的结果类型。
//1、decltype会保留变量的顶层const
const int ci = 0, &cj = ci;
decltype(ci) x = 0; //x的类型是const int
decltype(cj) y = x; //y的类型是const int&,y是x的别名
//decltype(cj) z; //z的类型是const int&,引用必须初始化
//2、表达式的内容是解引用操作,则decltype将得到引用类型
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; //b是一个未初始化的int
decltype(*p) c = i; //c是int&,必须初始化
//3、decltype的表达式如果是加上了括号的变量,结果会变成引用
decltype((i)) d = i; //d是int&,必须初始化
decltype(i) e; //e是一个未初始化的变量
//4、decltype((variable))的结果永远是引用,(注意是双括号)
auto和decltype的区别
1、auto类型说明符用编译器计算变量的初始值来推断其类型,而decltype虽然也让编译器分析表达式并得到它的类型,但是不实际计算表达式的值。
2、auto一般会忽略顶层const而只保留底层const,但是decltype却会将底层const保留。
3、与auto不同,decltype的结果类型与表达式形式密切相关。如果decltype使用的是不加括号的变量,得到的结果是该变量的类型;如果给变量加上了一层或多层括号,编译器将会得到的是引用类型。