一.auto关键字简介
auto这个关键字并不是一个全新的关键字,在旧标准中,它代表的是“具有自动存储期的局部变量”;但是它在这方面并没有起到很大的作用,比如:auto int i = 10 与int i = 10是等价的, 在旧标准中我们很少会用到auto关键字,因为非静态变量在默认的情况下本就是“具有自动存储期的”。
考虑到在旧标准中auto关键字用的很少。在C++11新特性中,auto关键字不在表示存储类型指示符,而是把它改成了一个类型指示符,用来提示编译器对此类型变量做类型的自动推导。
二.auto的推导规则
下述示例需要在支持C++11新特性的编译器中执行,否则会出现编译错误
#include <iostream> using namespace std; int main() { int x = 10; auto *a = &x; //auto被推导为int auto b = &x; //auto被推导为int* auto &c = x; //auto被推导为int auto d = c; //auto被推导为int const auto e = x; //auto被推导为int auto f = e; //auto被推导为int const auto& g = x; //auto被推导为int auto& h = g; //auto被推导为int return 0; }
A.d的推导结果说明了当表达式是一个引用类型时,auto会把引用类型抛弃,直接推导成原始类型int;
B.f的推导结果说明了当表达式带有const属性时,auto会把const属性抛弃掉,直接推导成int类型;
C.g和h的推导说明了当auto和引用(换成指针在这里也将得到同样的结果)结合时,auto的推导将保留变量的const属性
下面是上述推导A的验证实例
#include <iostream> using namespace std; int main() { int x = 10; const auto z = x; auto y = z; y = 10; cout << y << endl; const int a = 10; a = 20; cout << a << endl; return 0; }
在C++中,const int a = 10;初始化完成后,在为a赋值为20,编译器便会报错。如下所示:
a现在只是一个可读变量,不可在更改它的初始值;所以说,如果上述y变量类型推导为const int,再为y赋值的话,在编译时会报出同样的错误,但在编译时并未出现上述错误,那就说明在进行类型推导时,把const属性给抛弃掉了,只保留了一个原始类型int.
下面是上述推导C的验证实例
#include <iostream> using namespace std; int main() { int x = 10; const auto& z = x; z = 20; cout << z << endl; return 0; }
编译后会出现如下错误:
可以看出z只是一个只读引用,即const int &类型,不能再为其赋值。
从以上示例可以总结出下面两条规则
(1).当不声明为指针或引用时,auto的推导结果和初始化表达式抛弃引用和cv限定符(const和volatile限定符的统称)。
(2).当声明为指针或引用时,auto的推导结果将保持初始化表达式的cv属性。
三.auto的使用范围
auto关键字不是说在任何地方都能适用的;
(1).不能作为函数的形参
(2).不能用于非静态成员变量
(3).auto无法定义数组
(4).auto无法推导出模板参数
示例如下:
#include <iostream> #include <list> using namespace std; struct MyStruct { auto nValue = 0; //错误: 非静态的成员变量 static const auto value = 10; }; void MyPrintf(auto i) //警告:在参数声明中使用“auto”只能用-STD= C++1Y或-STD= GNU+1Y: { cout << i << endl; } int main() { auto array[10] = {0}; //错误:无法定义数组 list<auto> MyList; //错误:无法推导出模板的参数类型 auto i = 10; MyPrintf(i); return 0; }
那么在什么时候使用auto关键字呢?当变量定义过于冗长时,可以考虑使用auto关键字代替;比如说C++去遍历一个stl容器,迭代器定义时比较累赘,换成auto关键之后是不是瞬间清爽了不少。
#include <iostream> #include <vector> using namespace std; int main() { vector<int> MyVector; //插入数据 for(int i = 0; i < 10; i++) { MyVector.push_back(i); } //旧特性中遍历数据 vector<int>::iterator it = MyVector.begin(); for(; it != MyVector.end(); it++) { cout << *it <<","; } cout << endl; //新特性中遍历数据 auto MyIt = MyVector.begin(); for(; MyIt != MyVector.end(); MyIt++) { cout << *MyIt << ","; } return 0; }