C++11新特性中auto 和 decltype 区别和联系
C++11新特性中auto和decltype区别和联系
一.auto简介
编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型。然而做到这一点并非那么容易(特别是模板中),有时候根本做不到。为了解决这个问题,C++11新标准就引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。和原来那些只对应某种特定的类型说明符(例如int)不同。auto让编译器通过初始值来进行类型推演。从而获得定义变量的类型,所以说auto定义的变量必须有初始值。
//由val_1和val_2相加的结果可以推断出item的类型 autoitem=val_1+val_2;//item类型初始化为val_1+val_2相加后的类型,值为val_1+val_2相加的值。
这里的item的类型是编译器在编译的过程中通过val_1和val_2的类型相加后推算出来的。假如是val_1(int)+val_2(double),那么item的类型就是double.
使用auto也能在一个语句中声明多个变量,因为一个声明雨具只能有一个基本数据类型,所以该雨具所有变量的初始基本数据类型都必须是一样的。在这里一定要区别数据类型和类型修饰符!!
inti=3; autoa=i,&b=i,*c=&i;//正确:a初始化为i的副本,b初始化为i的引用,c为i的指针. autosz=0,pi=3.14;//错误,两个变量的类型不一样。
编译器推断出来的auto类型有时候会跟初始值的类型并不完全一样,编译器会适当的改变结果类型使得其更符合初始化规则。
首先,正如我们熟知的,使用引用其实是使用引用的对象,特别当引用被用作初始值的时候,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型:
inti=0,&r=i;//定义一个整数i,并且定义r为i的应用. autoa=r;//这里的a为为一个整数,其值跟此时的i一样.
由此可以看出auto会忽略引用,其次,auto一般会忽略掉顶层const,但底层const会被保留下来,比如当初始值是一个指向常量的指针时:
inti=0; constintci=i,&cr=ci;//ci为整数常量,cr为整数常量引用 autoa=ci;//a为一个整数,顶层const被忽略 autob=cr;//b为一个整数,顶层const被忽略 autoc=&ci;//c为一个整数指针. autod=&cr;//d为一个指向整数常量的指针(对常量对象区地址是那么const会变成底层const)
如果你希望推断出auto类型是一个顶层的const,需要明确指出:
constautof=ci;
还可以将引用的类型设为auto,此时原来的初始化规则仍然适用(用于引用声明的const都是底层const):
auto&g=ci;//g是一个整数常量引用,绑定到ci。 auto&h=42;//错误:非常量引用的初始值必须为左值。 constauto&j=42;//正确:常量引用可以绑定到字面值。
二.decltype简介
有的时候我们还会遇到这种情况,我们希望从表达式中推断出要定义变量的类型,但却不想用表达式的值去初始化变量。还有可能是函数的返回类型为某表达式的的值类型。在这些时候auto显得就无力了,所以C++11又引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器只是分析表达式并得到它的类型,却不进行实际的计算表达式的值。
decltype(f())sum=x;//sum的类型就是函数f的返回值类型。
在这里编译器并不实际调用f函数,而是分析f函数的返回值作为sum的定义类型。
基本上decltype的作用和auto很相似,就不一一列举了。对于decltype还有一个用途就是在c++11引入的后置返回类型。
三.decltype和auto区别
decltype在处理顶层const和引用的方式与auto有些许不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)。
constintci=42,&cj=ci; decltype(ci)x=0;//x类型为constint autoz=ci;//z类型为int decltype(cj)y=x;//y类型为constint& autoh=cj;//h类型为int
decltype还有一些值得注意的地方,我们先来看看下面这段代码:
inti=42,*p=&i,&r=i; decltype(i)x1=0;//因为i为int,所以x1为int autox2=i;//因为i为int,所以x2为int decltype(r)y1=i;//因为r为int&,所以y1为int& autoy2=r;//因为r为int&,但auto会忽略引用,所以y2为int decltype(r+0)z1=0;//因为r+0为int,所以z1为int, autoz2=r+0;//因为r+0为int,所以z2为int, decltype(*p)h1=i;//这里h1是int&,原因后面讲 autoh2=*p;//h2为int.
如果表达式的内容是解引用操作,则decltype将得到引用类型。正如我们所熟悉的那样,解引用指针可以得到指针所指对象,而且还可以给这个对象赋值。因此decltype(*p)的结果类型就是int&.
decltype和auto还有一处重要的区别是,decltype的结果类型与表达形式密切相关。有一种情况需要特别注意:对于decltype所用表达式来说,如果变量名加上一对括号,则得到的类型与不加上括号的时候可能不同。如果decltype使用的是一个不加括号的变量,那么得到的结果就是这个变量的类型。但是如果给这个变量加上一个或多层括号,那么编译器会把这个变量当作一个表达式看待,变量是一个可以作为左值的特殊表达式,所以这样的decltype就会返回引用类型:
inti=42; //decltype(i)int类型 //decltype((i))int&类型
这里再指出一个需要注意的地方就是=赋值运算符返回的是左值的引用。换句话意思就是说decltype(i=b) 返回类型为i类型的引用。仔细看下面这段代码:
intmain() { inti=42; decltype(i=41)x=i; autoy=i; auto&z=i; printf("ixyz此时为:%d%d%d%d\n",i,x,y,z); i--; printf("ixyz此时为:%d%d%d%d\n",i,x,y,z); x--; printf("ixyz此时为:%d%d%d%d\n",i,x,y,z); y--; printf("ixyz此时为:%d%d%d%d\n",i,x,y,z); z--; printf("ixyz此时为:%d%d%d%d\n",i,x,y,z); return0; }
运行结果为:
ixyz此时为:42424242 ixyz此时为:41414241 ixyz此时为:40404240 ixyz此时为:40404140 ixyz此时为:39394139
由上面的代码和运行结果可以看出来,1.decltype(i=41)中的赋值语句并没有真正的运行。2.decltype(i=41)返回的其实是int&,也就是说x其实是i的引用。
了解了auto和decltype后,以后在使用的过程中一定要分清两者的区别,防止在定义的时候产生const与非const以及引用与非引用的差别!!
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!