随着程序越来越复杂,有时侯根本搞不清到底需要的类型是什么,程序员不得不回过头去从程序的上下文中寻求帮助。但 auto类型说明符能让编译器通过初始值来推算变量的类型。显然,auto定义的变量必须有初始值。
使用auto也能在一条语句中声明多个变量。因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一样:
auto i = 0, *p = &i; //i是整数,p是整型指针特别的,当引用被用作初始值时,真正参与初始化的其实是引用对象的值,因为使用引用其实是使用引用的对象。此时编译器以引用对象的类型作为auto的类型:
int i =0, &r = i; auto a = r; //a是一个整数(r是i的别名,而i是一个整数)其次,auto一般会忽略掉顶层const,同时底层const则会保留下来:
const int ci=i, &cr=ci; auto b=ci; //int变量(ci的顶层const被忽略) auto c=cr; //int变量 auto d=&i; //指向int变量的指针 auto e=&ci; //指向int常量的指针(对常量对象取地址是一种底层const) auto &g=ci; //int型常量引用先简单介绍一下常量引用:
auto &g=ci; auto &h=42; //非法,不能为非常量引用绑定字面值 const auto &j=42 //合法,可以为常量引用绑定字面值常量引用的const是底层const,其引用的对象值为常量。
为什么写 auto &g = ci; 推导之后const却留下来了?
答:顶层const只有拷贝初始化的时候才会被auto丢弃:
auto k = ci; // 拷贝语义:复制ci的值生成独立新变量k,顶层const作用对象只是旧变量ci, //所以k不需要继承这个const,k的类型为int而 auto &g = ci; 是引用绑定,并非拷贝:
引用不会复制出新数据,g直接绑定ci对应的那块内存。此时限制“这块内存的值不能改动”的const,身份发生了视角切换:
- 站在 ci 本身的角度:const约束ci自己,属于顶层const;
- 站在引用g的视角:g访问的是下层被绑定的数据,这个const就转变为底层const,用来约束引用指向的内容不可修改。
auto推导引用的时候会保留底层const,因此最终 g 得到 const int& 。
如果希望推断出的auto类型是一个顶层const,需要明确指出:
const auto f = ci; //int常量切记,符号&和*只从属于某个声明符,而非基本数据类型的一部分,因此初始值必须是同一个类型:
auto k=ci,&l=i; //k是整数,l是整数引用 auto &m=ci,*p=&ci; //m是对整型常量的引用,p是指向整型常量的指针 auto &n=i,*p2=&ci; //非法 i的类型是int,而&ci的类型是const int