auto关键字解析
前言
在11
标准之前,auto
在c++
中是声明存储器类型的关键字。而在11
标准中它的功能变为了类型推导。
对此, 在这里引入C++primer
中的原句:
编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚的知道表达式的类型。然而要做到这一点并非那么容易,有时候甚至根本做不到。为了解决这个问题,C++11
新标准引入了auto
类型说明符,用它就能让编译器替我们去分析表达式所属的类型。和原来的那些对应的一种特定类型的说明符不同,auto
让编译器通过初始值来推断变量的类型。显然,auto
定义的变量必须具有初始值。
比如下面的代码:
vector<int> vtr{ 0, 1, 2, 3, 4 };for (auto x : vtr)cout << x << ' ';
可以看出auto
设计的基本思想就是想通过简短的auto
占位符替代程序中长且杂的各种数据类型。从而增大开发效率。
显然想要auto
实现这一目的需要满足——auto
必须能够表示出程序中的所有数据类型。
auto
的组合使用
auto
不仅仅能够表示单独的数据类型,还可以和&
,*
等类型标识符配合使用组成其他的数据类型,比如:
int x = 0;auto *pt1 = &x; // pt1为int*, auto推导为 intauto pt2 = &x; // pt2为int*, auto推导为int*auto& r1 = x; // r1为int&, auto推导为intauto r2 = r1; // r2为int,auto推导为int
指针和引用作为栈区数据的左膀右臂,若只使用auto
关键字,想要达到将int
赋值给引用这种操作显然是做不到的。
int
在赋值给auto
时会不明确auto
到底是普通类型还是引用类型而产生二义性,为了避免二义性,规定int
类型赋值给auto
依旧是int
类型,若想要赋值给引用类型需要auto
和&
配合使用。
这也与auto
表示所有类型的理念不约而和。
auto
与const
前面讲述和auto
在设计时为了避免二义性会进行取舍操作,保证一种声明赋值语句只会对应一种类型。
但是这样同样会衍生一个问题——在避免二义性得时候如何选择。
假设我们作为C++
语言的设计者,在选择时肯定会更偏向于更自由的一方,毕竟C++
的设计理念就是既想保留C
的自由,又想发展自己的东西。
接下来我就会列举几个auto
个const
的组合。并从是否合法,涵盖全面,更自由的选择等方面来分析编译器为何会如此选择。
要补充一点,可能有的时候看似auto
有多种选择,因为在C++
中赋值语句是支持隐式类型转换的,但是实际上auto
作为"万能的数据类型",其在设计时就应当规避掉类型转换的操作,所以在分析时我不会考虑类型转换的选择。
int x = 0;const auto n = x; // auto会被推导为 intauto f = n; // const在取值时没有限定,因此编译器会将auto处理为int,显然int会比const int涵盖面更广const auto& r1 = x; // auto会被翻译成int, 当然也有可能会被翻译成const int, 不过在编译器中多个const和一个const效果相同// int& r3 = n; 这样赋值编译器会报错auto& r2 = n; // r2会被翻译成const int, 因为const int数值是不能赋值给int引用的,所以编译器选择const int
-
const auto n = x
:x
为int
类型,而auto
前面有const
限定符,显然这里的auto
只能被推导为int
类型。 -
auto f = n
:前面我们分析了n
为const int
类型,而const int
类型允许赋值给const int
,和int
类型,有两种选择,最终选择int
。主要从两方面分析,一方面是我们所说的自由性,若想要赋值给
const int
类型可以在auto
前加上const
限定符。而
const int
无法添加限定符将其变为int
类型,所以显然int
要比const int
更自由。另一方面,如果
auto
在这里被推导为const int
类型,那么你会发现没有一种情况可以使const int
类型赋值给auto
时auto
被推导为int
了,这违背了auto
的设计理念。 -
const auto& r1 = x
:会被翻译为int
,不多讨论。 -
auto& r2 = n
:n
为const int
类型,而在c++
中只允许const int
类型赋值给const int&
类型(这里不是说不能赋值给其他,只是说若要赋值给引用则必须加const
限定符),所以这里也只能是const int&
。
总结
借用C++primer
中的一句话:
auto
一般会忽略掉顶层const
,同时底层const
则会保留下来。
比如在a = b
这种赋值语句中,尽管b
有const
限定,但其实a
是直接将b
中的数据拷贝过来,auto
会直接忽略掉const
。
而在&a = b
这种语句中,a
实际上是保存的b
的地址,auto
就会保留下const
。