1.  auto关键字

(1)auto的作用是让编译器自动推断变量的类型,而不需要显式指定类型。这种隐式类型的推导发生在编译期

(2)auto并不能代表实际的类型声明,只是一个类型声明的“占位符”

(3)auto声明的变量必须马上初始化,以让编译器推断出它的实际类型。

【编程实验】auto的基本用法

//1.1.cpp

  1. #include <iostream>
  2. #include <typeinfo>
  3.  
  4. //编译:vc: cl 1.1.cpp
  5. // g++: g++ -std=c++11 1.1.cpp
  6.  
  7. using namespace std;
  8.  
  9. double foo(){return 0.0;};
  10.  
  11. struct m{
  12. int i;
  13. }sm;
  14.  
  15. int main()
  16. {
  17. auto x = ; //x:int(其实1为const int类型,auto丢弃const)
  18. auto y = foo(); //y:double
  19. auto z = sm; //m1: struct m
  20.  
  21. const auto* u = &x, v = ; //u: const int*, v: int类型(注意不是const int)
  22. //auto的类型由u的类型决定,因此v不能初始化为6.0之类
  23. static auto w = 0.0; //w:double;
  24.  
  25. //auto s; //error: 无法推导。s必须被初始化
  26.  
  27. cout << "x: " << typeid(x).name() << endl;
  28. cout << "y: " << typeid(y).name() << endl;
  29. cout << "z: " << typeid(z).name() << endl;
  30. cout << "u: " << typeid(u).name() << endl;
  31. cout << "v: " << typeid(v).name() << endl;
  32. cout << "w: " << typeid(w).name() << endl;
  33.  
  34. return ;
  35. }
  36. /*输出结果:
  37. x: int
  38. y: double
  39. z: struct m
  40. u: int const *
  41. v: int
  42. w: double
  43. */

2. auto的推导规则

(1)当直接使用auto声明变量时(如auto varName),auto的推导结果和初始化表达式抛弃引用cv限定符(const和volatile)后的类型一致。即auto将丢弃初始化表达式的cv属性。(原因 :auto varName说明varName是按值传递,它是原对象/变量的副本,所以可以在副本上进行修改操作,所以并不需要保留const等属性)

(2)当auto后面显式添加&时(如auto& varName)时,推导结果才会保留初始化表达式的cv属性和引用。(原因:由于引用代表对象本身,所以原对象/变量如果有cv属性,则应该被保留下来)

(3)当auto*或auto推导结果为指针,保留指针的底层cv操作符。除2、3两种情况外,均不保留cv和引用。

(4)同一赋值语句中,用auto来声明多个变量类型时,只有第一个变量用于auto的类型推导,然后推导出来的数据类型作用于其他变量。因此,这些变量的类型必须相同。否则,编译器则会报错。

(5)auto是从左向右推导,类似于字面替换的方式进行。

(6)new和初始化列表中也可以使用auto关键字

【实例分析】auto和auto&(auto*)的差异

//1.2.cpp

  1. #include <iostream>
  2. #include <typeinfo>
  3. using namespace std;
  4.  
  5. //编译:vc: cl 1.2.cpp
  6. // g++: g++ -std=c++11 1.2.cpp
  7.  
  8. double foo(){return 0.0;};
  9.  
  10. int main()
  11. {
  12. auto x = ; //x: int(注意1为const int类型,但auto会丢弃const限定符)
  13. int* y=&x;
  14.  
  15. auto* a = &x; //a: int* auto: int
  16. auto b = &x; //b: int* auto: int*
  17. auto& c = x; //c: int&, auto: int
  18.  
  19. //auto和auto&:当初始化表达式为引用时
  20. auto d = c; //d: int, auto: int(注意:c为引用,但会被auto会丢弃,故d为int)
  21. auto& e = c; //e: int&, auto: int(auto&会保留引用和cv限制符)
  22.  
  23. //auto和auto&: 当初始化表达式带cv限定符时
  24. const auto f = x; //f: const int, auto: int
  25. auto g = f; //注意此处:g: int(因为auto会丢弃初始化表达式的cv限定符)
  26.  
  27. auto& h = f; //注意此处:h:const int&(auto&会保留f的const属性)
  28. auto* i = &f; //注意此处:i:const int*(auto*会保留f的const属性)
  29.  
  30. //auto从左向右推导
  31. auto o = , &p = o, *q = &p; //o: int, p: int&, q: int*
  32. auto r = , s = ; //auto根据r推导出auto为int,因此s为int
  33.  
  34. //单行声明变量的陷阱(建议:多变量尽量分多行声明)
  35. const auto* m = &x, n = ; //m: const int*,但n为int(注意不带const)
  36.  
  37. //初始化列表中使用auto
  38. auto x1(); //x1: int
  39. auto x2 {}; //x2: int
  40.  
  41. //new中使用auto
  42. auto x3 = new auto();
  43.  
  44. cout << "a: " << typeid(a).name() << endl;
  45. cout << "b: " << typeid(b).name() << endl;
  46. cout << "c: " << typeid(c).name() << endl;
  47. cout << "d: " << typeid(d).name() << endl;
  48. cout << "e: " << typeid(e).name() << endl;
  49. cout << "f: " << typeid(f).name() << endl;
  50. cout << "g: " << typeid(g).name() << endl;
  51. cout << "h: " << typeid(h).name() << endl;
  52. cout << "i: " << typeid(i).name() << endl;
  53. cout << "o: " << typeid(o).name() << endl;
  54. cout << "p: " << typeid(p).name() << endl;
  55. cout << "q: " << typeid(q).name() << endl;
  56. cout << "r: " << typeid(r).name() << endl;
  57. cout << "m: " << typeid(m).name() << endl;
  58. cout << "n: " << typeid(n).name() << endl;
  59. cout << "x1: " << typeid(x1).name() << endl;
  60. cout << "x2: " << typeid(x2).name() << endl;
  61. cout << "x3: " << typeid(x3).name() << endl;
  62.  
  63. return ;
  64. }
  65. /*输出结果
  66. a: int *
  67. b: int *
  68. c: int
  69. d: int
  70. e: int
  71. f: int
  72. g: int
  73. h: int
  74. i: int const *
  75. o: int
  76. p: int
  77. q: int *
  78. r: int
  79. m: int const *
  80. n: int
  81. x1: int
  82. x2: int
  83. x3: int *
  84. */

3. auto的限制

(1)auto不能用于函数参数。如果需要泛型参数,可借助于模板

(2)auto不能用于非静态成员变量

(3)auto无法定义数组

(4)auto无法推导模板参数

【实例分析】auto使用受限

//1.3.cpp

  1. #include <iostream>
  2. #include <vector>
  3. #include <typeinfo>
  4. using namespace std;
  5.  
  6. //编译:vc: cl 1.3.cpp
  7. // g++: g++ -std=c++11 1.3.cpp
  8.  
  9. void func(auto a = ){} //error: 不能用于函数参数。泛型参数可借助模板来实现
  10.  
  11. struct Foo
  12. {
  13. static const auto var2 = ; //OK: 静态成员函数,可用auto推导
  14.  
  15. auto var1 = ; //error:非静态成员函数,不能用auto推导
  16. };
  17.  
  18. int main()
  19. {
  20. char x[] ={};
  21. auto y = x; //OK: y: int*(注意:不是char[3])
  22. auto z[] = x; //error: auto无法定义数组
  23.  
  24. vector<auto> v = {}; //error: auto不能用于模板参数
  25.  
  26. return ;
  27. }

4. auto的优势

(1)auto最大优势简化代码,特别是当声明的变量类型比较复杂的时候。

(2)避免类型声明时的错误。C/C++存在很多隐式或用户自定义的类型转换规则,这些规则不容易记忆,这时auto就可以用于自动推导。

(3)auto的“自适应”能够在一定程序上支持泛型编程。如strlen函数返回值,在32位编译环境下,返回一个4字节的整型,64位返回一个8字节的整型。可以使用auto关键字达到代码跨平台的效果。

【实例分析】auto的优势

//1.4.cpp

  1. #include <iostream>
  2. #include <map>
  3.  
  4. //编译:vc: cl 1.4.cpp
  5. // g++: g++ -std=c++11 1.4.cpp
  6.  
  7. //1. 简化迭代器变量的声明
  8. void func()
  9. {
  10. std::map<double, double> resMap;
  11. //优化前
  12. // std::map<double, double>::iterator = it = resMap.begin();
  13. // for(; it != resMap.end(); ++it){
  14. // //do something;
  15. // }
  16.  
  17. //优化后
  18. for(auto it = resMap.begin(); it != resMap.end(); ++it){
  19. //do something
  20. }
  21. }
  22.  
  23. //2. 避免类型声明错误
  24. class PI
  25. {
  26. const float val = 3.1415927f;
  27. public:
  28. double operator* (float v){
  29. return (double)val * v; //精度被扩展
  30. }
  31. };
  32.  
  33. //3. auto对类型的自适应
  34. template <typename T1, typename T2>
  35. double Sum(T1& t1, T2& t2)
  36. {
  37. auto s = t1 + t2; //s的类型会在模板实例化时被推导出来
  38. }
  39.  
  40. int main()
  41. {
  42. //demo: 避免auto类型声明
  43. float radius = 1.7e10;
  44. PI pi;
  45.  
  46. //operator*的返回值为double,但使用PI这个类的人可能不知道
  47. //PI类的设计者为了避免数据上溢而返回了double类型。这时可以
  48. //用auto来自动推导operator*的返回类型。同时假如PI的作者改动
  49. //了PI的定义,将operator*的返回值改为了long double,此时main
  50. //函数并不需要修改,因为auto会“自适应”新的类型
  51. auto circumference = * (pi * radius);
  52.  
  53. //demo: auto的自适应
  54. int a = ;
  55. long b = ;
  56. float c = 1.0f, d = 2.3f;
  57. auto e = Sum<int, long>(a, b); //s==> long;
  58. auto f = Sum<float, float>(c, d); //s==>float;
  59.  
  60. return ;
  61. }

第1课 类型推导(1)_auto关键字的更多相关文章

  1. 第2课 类型推导(2)_decltype关键字

    1. decltype关键字 (1)auto所修饰的变量必须被初始化,编译器才能通过初始化来确定auto所代表的类型,即必须先定义变量. (2)decltype可以在编译期推导出一个变量或表达式的结果 ...

  2. 第4课 decltype类型推导

    第4课 decltype类型推导 一.decltype类型推导 (一)语法: 1.语法:decltype(expr),其中的expr为变量(实体)或表达式 2.说明: ①decltype用于获取变量的 ...

  3. C++11 - 类型推导auto关键字

    在C++11中,auto关键字被作为类型自动类型推导关键字 (1)基本用法 C++98:类型 变量名 = 初值;   int i = 10; C++11:auto 变量名 = 初值;  auto i ...

  4. 第3课 auto类型推导(2)

    第3课 auto类型推导(2) 一.使用auto的优势 (一)避免使用未初始化变量 (二)可简化变量/对象类型的声明 (三) 在某些场合无法判断出类型时,可用auto自动推导(如lambda表达式) ...

  5. 第2课 auto类型推导(1)

    第2课 auto类型推导(1) 一.auto类型推导 (一)与模板类型推导映射关系 1.auto类型推导与模板类型推导可以建立一一映射关系,它们之间存在双向的算法变换.auto扮演模板中T的角色,而变 ...

  6. c++相关的类型推导

    c++11和boost库增加许多关于类型推导(编译期)的关键字和类型, 用好这些机制, 对于编写项目的一些组件帮助颇大.正所谓工欲善其事,必先利其器. 1.初始化某种类型的变量 auto var = ...

  7. Swift学习(三)类型推导&基本运算&分支&循环

    一.Swift中类型推导&基本运算 Swift中类型推导 如果一个标识符在定义时有直接赋值,那么可以根据后面赋值的类型,来推导出前面标识符的类型,这样前面标识符的(:类型)可以省略 查看标识符 ...

  8. C++11类型推导

    [C++11类型推导] auto 关键字.这会依据该初始化子(initializer)的具体类型产生参数: 除此之外,decltype 能够被用来在编译期决定一个表示式的类型. 参考:http://z ...

  9. 《Effective Modern C++》翻译--条款2: 理解auto自己主动类型推导

    条款2: 理解auto自己主动类型推导 假设你已经读过条款1关于模板类型推导的内容,那么你差点儿已经知道了关于auto类型推导的所有. 至于为什么auto类型推导就是模板类型推导仅仅有一个地方感到好奇 ...

随机推荐

  1. 03C++语言对C的增强——实用性、变量检测、struct类型、C++中所有变量和函数都必须有类型、bool类型、三目运算符

    1.“实用性”增强 C语言中的变量都必须在作用域开始的位置定义,C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义. 2.C++对c语言register的增强 register关键字 ...

  2. [转]ArrayList的实现原理

    1. ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类还提供一些方法来操作内部 ...

  3. mongodb之 非正常关闭启动报错处理

    Mongodb如果非正常关闭,直接启动会报错.查看日志文件. 处理: 需要做的是删除mongod.lock和WiredTiger.lock这两个lock文件,然后执行--repair,这里的mongo ...

  4. TypeScript 之 tsconfig.json

    https://m.runoob.com/manual/gitbook/TypeScript/_book/doc/handbook/tsconfig.json.html 如果一个目录下存在一个tsco ...

  5. js实现表单提交 onsubmit

    <!--HTML--> <form role="form" class="form-edit-add edit-form" action=&q ...

  6. mysql二进制日志详解

    一.什么是二进制日志 二进制日志主要记录mysql数据库的变化,二进制日志包含所有更新了数据或者潜在更新了数据(如没有匹配到任何行的delete语句),语句以时间的形式保存,描述了数据的更改.二进制日 ...

  7. excel技巧--一键求和

    类似于上图的表格,我们要得到右侧和下侧栏的汇总结果,通常可以用sum公式加下拉方式,但是还有一种方法更快速,那就是使用 ALT + “+=”组合键就能一下子得到所有汇总结果.(+=键,就是一个键,该键 ...

  8. iphone越狱安装python2.7

    cydia  添加源地址:http://apt.so/whitefur 选择python 进行安装 打开ssh连接后输入python 显示python2.7.3 安装成功

  9. Xshell存在后门

    Xshell 它是一款终端模拟软件,由NetSarang公司出品,支持SSH1.SSH2和Windows系统中Telnet协议. 简介 卡巴斯基实验室在8月7日发现Xshell软件中的nssock2. ...

  10. InfluxDB 1.6文档

    警告!此页面记录了不再积极开发的InfluxDB的早期版本.InfluxDB v1.7是InfluxDB的最新稳定版本. InfluxDB是一个时间序列数据库,旨在处理高写入和查询负载.它是TICK堆 ...