一.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; }