转自: here

一. auto简介

编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型。然而做到这一点并非那么容易(特别是模板中),有时候根本做不到。为了解决这个问题,C++11新标准就引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。和原来那些只对应某种特定的类型说明符(例如 int)不同。auto 让编译器通过初始值来进行类型推演。从而获得定义变量的类型,所以说 auto 定义的变量必须有初始值。

  1. //由val_1 和val_2相加的结果可以推断出item的类型
  2. auto item = 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也能在一个语句中声明多个变量,因为一个声明雨具只能有一个基本数据类型,所以该雨具所有变量的初始基本数据类型都必须是一样的。在这里一定要区别数据类型和类型修饰符!!

  1. int i = 3;
  2. auto a = i,&b = i,*c = &i;//正确: a初始化为i的副本,b初始化为i的引用,c为i的指针.
  3. auto sz = 0, pi = 3.14;//错误,两个变量的类型不一样。

编译器推断出来的auto类型有时候会跟初始值的类型并不完全一样,编译器会适当的改变结果类型使得其更符合初始化规则。

首先,正如我们熟知的,使用引用其实是使用引用的对象,特别当引用被用作初始值的时候,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型:

  1. int i = 0 ,&r = i;//定义一个整数i,并且定义r为i的应用.
  2. auto a = r; //这里的a为为一个整数,其值跟此时的i一样.

由此可以看出auto会忽略引用,其次,auto一般会忽略掉顶层const,但底层const会被保留下来,比如当初始值是一个指向常量的指针时:

  1. int i = 0;
  2. const int ci = i, &cr = ci;  //ci 为整数常量,cr 为整数常量引用
  3. auto a = ci;     // a 为一个整数, 顶层const被忽略
  4. auto b = cr;     // b 为一个整数,顶层const被忽略
  5. auto c = &ci;    // c 为一个整数指针.
  6. auto d = &cr;    // d 为一个指向整数常量的指针(对常量对象区地址是那么const会变成底层const)

如果你希望推断出auto类型是一个顶层的const,需要明确指出:

  1. const auto f = ci;

还可以将引用的类型设为auto,此时原来的初始化规则仍然适用(用于引用声明的const都是底层const):

  1. auto &g = ci; //g是一个整数常量引用,绑定到ci。
  2. auto &h = 42; // 错误:非常量引用的初始值必须为左值。
  3. const auto &j = 42; //正确:常量引用可以绑定到字面值。

二. decltype简介

有的时候我们还会遇到这种情况,我们希望从表达式中推断出要定义变量的类型,但却不想用表达式的值去初始化变量。还有可能是函数的返回类型为某表达式的的值类型。在这些时候auto显得就无力了,所以C++11又引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器只是分析表达式并得到它的类型,却不进行实际的计算表达式的值。

  1. decltype(f()) sum = x;// sum的类型就是函数f的返回值类型。

在这里编译器并不实际调用f函数,而是分析f函数的返回值作为sum的定义类型。

基本上decltype的作用和auto很相似,就不一一列举了。对于decltype还有一个用途就是在c++11引入的后置返回类型。

三. decltype 和 auto 区别

decltype在处理顶层const和引用的方式与auto有些许不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)。

  1. const int ci = 42, &cj = ci;
  2. decltype(ci) x = 0;   // x 类型为const int
  3. auto z = ci;          // z 类型为int
  4. decltype(cj) y = x;   // y 类型为const int&
  5. auto h = cj;          // h 类型为int

decltype还有一些值得注意的地方,我们先来看看下面这段代码:

  1. int i = 42, *p = &i, &r = i;
  2. decltype(i) x1 = 0;       //因为 i 为 int ,所以 x1 为int
  3. auto x2 = i;              //因为 i 为 int ,所以 x2 为int
  4. decltype(r) y1 = i;       //因为 r 为 int& ,所以 y1 为int&
  5. auto y2 = r;              //因为 r 为 int& ,但auto会忽略引用,所以 y2 为int
  6. decltype(r + 0) z1 = 0;   //因为 r + 0 为 int ,所以 z1 为int,
  7. auto z2 = r + 0;          //因为 r + 0 为 int ,所以 z2 为int,
  8. decltype(*p) h1 = i;      //这里 h1 是int&, 原因后面讲
  9. auto h2 = *p;             // h2 为 int.

如果表达式的内容是解引用操作,则decltype将得到引用类型。正如我们所熟悉的那样,解引用指针可以得到指针所指对象,而且还可以给这个对象赋值。因此decltype(*p)的结果类型就是int&.

decltype和auto还有一处重要的区别是,decltype的结果类型与表达形式密切相关。有一种情况需要特别注意:对于decltype 所用表达式来说,如果变量名加上一对括号,则得到的类型与不加上括号的时候可能不同。如果decltype使用的是一个不加括号的变量,那么得到的结果就是这个变量的类型。但是如果给这个变量加上一个或多层括号,那么编译器会把这个变量当作一个表达式看待,变量是一个可以作为左值的特殊表达式,所以这样的decltype就会返回引用类型:

  1. int i = 42;
  2. //decltype(i)   int  类型
  3. //decltype((i)) int& 类型

这里再指出一个需要注意的地方就是 = 赋值运算符返回的是左值的引用。换句话意思就是说 decltype(i = b)  返回类型为 i 类型的引用。仔细看下面这段代码:

  1. int main()
  2. {
  3. int i = 42;
  4. decltype(i = 41) x = i;
  5. auto y = i;
  6. auto& z = i;
  7. printf("i x y z 此时为: %d %d %d %d\n", i,x,y,z);
  8. i--;
  9. printf("i x y z 此时为: %d %d %d %d\n", i, x, y, z);
  10. x--;
  11. printf("i x y z 此时为: %d %d %d %d\n", i, x, y, z);
  12. y--;
  13. printf("i x y z 此时为: %d %d %d %d\n", i, x, y, z);
  14. z--;
  15. printf("i x y z 此时为: %d %d %d %d\n", i, x, y, z);
  16. return 0;
  17. }

运行结果为:

i x y z 此时为: 42 42 42 42
i x y z 此时为: 41 41 42 41
i x y z 此时为: 40 40 42 40
i x y z 此时为: 40 40 41 40
i x y z 此时为: 39 39 41 39

由上面的代码和运行结果可以看出来,1.decltype(i = 41)中的赋值语句并没有真正的运行。2. decltype(i = 41)返回的其实是int&,也就是说x 其实是 i 的引用。

了解了auto 和 decltype后,以后在使用的过程中一定要分清两者的区别,防止在定义的时候产生const 与非const 以及引用 非引用 的差别!!

c++11 auto 与 decltype 详解的更多相关文章

  1. [原创]java WEB学习笔记38:EL 中的 11个 隐含对象 详解

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  2. 11、mysql索引详解

    1.索引介绍: 2.建立索引的方法: 注意:索引名称不要相同: (1)在建表的时候,可以增加主键索引的语句如下: 1)例一: create table student1 ( id int(4) not ...

  3. C++11 std::chrono库详解

    所谓的详解只不过是参考www.cplusplus.com的说明整理了一下,因为没发现别人有详细讲解. chrono是一个time library, 源于boost,现在已经是C++标准.话说今年似乎又 ...

  4. Java基础11:Java泛型详解

    本文对java的泛型的概念和使用做了详尽的介绍. 本文参考https://blog.csdn.net/s10461/article/details/53941091 具体代码在我的GitHub中可以找 ...

  5. C++11 auto and decltype

    1.auto关键字 C++新标准引入auto关键词,此auto与之前C语言的auto意义已经不一样了. 这里的auto是修饰未知变量的类型,编译器会通过此变量的初始化自动推导变量的类型. 例如:aut ...

  6. 11.Linux启动过程详解

    目录: 本文转载自:http://blog.csdn.net/miss_acha/article/details/50004717 经过对Linux系统有了一定了解和熟悉后,想对其更深层次的东西做进一 ...

  7. C++11 auto和decltype推导规则

    VS2015下测试: decltype: class Foo {}; int &func_int_r(void) { int i = 0; return i; }; int && ...

  8. C++11 unique_ptr智能指针详解

    在<C++11 shared_ptr智能指针>的基础上,本节继续讲解 C++11 标准提供的另一种智能指针,即 unique_ptr 智能指针. 作为智能指针的一种,unique_ptr ...

  9. kafka的auto.offset.reset详解与测试

    1. 取值及定义 auto.offset.reset有以下三个可选值: latest (默认) earliest none 三者均有共同定义: 对于同一个消费者组,若已有提交的offset,则从提交的 ...

随机推荐

  1. Voltage Translation for Analog to Digital Interface ADC

    Voltage Translation for Analog to Digital Interface 孕龙逻辑分析仪 ZeroPlus Logic Analyzer How to modify an ...

  2. Android导入第三方静态库.a编译成动态库.so

    http://ikinglai.blog.51cto.com/6220785/1324985 在Android开发的时候,经常会使用到用c或c++编写的第三方的静态库.如果有源码的话,可以直接跟你自己 ...

  3. Scala:Next Steps in Scala

    Array val greetStrings = new Array[String](3) greetStrings(0) = "Hello" greetStrings(1) = ...

  4. No module named 'pandas._libs.tslib'

    用pip命令安装: pip install pandas python3的: pip3 install pandas

  5. libnids关于计算校验和引起的抓不到包的现象的解决方法

    libnids关于计算校验和引起的抓不到包的现象的解决方法: nids.h中有这么一段: struct nids_chksum_ctl { u_int netaddr; u_int mask; u_i ...

  6. XMPP增加删除好友

    在现阶段的通信服务中,各种标准都有,因此会出现无法实现相互连通,而XMPP(Extensible Message and presence Protocol)协议的出现,实现了整个及时通信服务协议的互 ...

  7. MySQL实用工具汇总

    本文收录了mysql相关的实用工具.工具包括:性能测试,状态分析,SQL路由,及运维开发相关的所有工具,并会持续更新. 1.工具套件集 - percona-toolkit - oak-toolkit ...

  8. Sublime美化配置

    1.主题预览 material主题:https://equinsuocha.io/material-theme/#/default 2.效果预览 { "ignored_packages&qu ...

  9. GDALSetProjection使用的一个注意事项

    GDALSetProjection 简述 GDALSetProjection是用来给GDALDataset设定投影信息(坐标系统)的接口,实际上是GDALDataset::SetProjection这 ...

  10. Axure RP for Mac(网站交互式原型设计工具)破解版安装

    1.软件简介    Axure RP 是 macOS 系统上一款最知名和最强大的原型设计工具,增加了大量新的特性,如应用多个动画,并同一时间运行一个小部件,如褪色,同时移动等,而且具有全新的图标和界面 ...