編程時常常需要把表達式的值賦給變量,這就要求在聲明變量的時候清楚知道表達式的類型。然而要做到這一點並非那麼容易,有時候甚至根本做不到。為了解決這個問題,C++11標准引入了auto
類型說明符,用它就能讓編譯器替我們去分析表達式所屬的類型。
與原來那些只對應一種特定類型的說明符不同,auto
讓編譯器通過初值來推算變量類型。顯然,auto
定義的變量必須要有初始值。
使用auto
具有以下幾點好處:
auto item = val1 + val2; // 由val1和val2相加的結果推斷出item的類型
auto i=0, *p = &i; // i是整數,p是整型指針
使用auto
能在一條語句中聲明多個變量。但是一條聲明語句只能有一個基本數據類型,所以該語句中所有變量的初始基本數據類型都必須一致:
auto sz = 0, pi = 3.14; // Error!
編譯器推斷出的auto
類型有時候和初始值的類型並不完全一樣,編譯器會適當地改變結果類型使其更符合初始化規則,例如:
auto
會刪除引用
int count = 10;
int& countRef = count;
auto myAuto = countRef;
countRef = 11;
cout << count << " "; // print 11
myAuto = 12;
cout << count << endl; // print 11
你可能會認為 myAuto
是一個 int
引用,但它不是。它只是一個 int
,因為輸出為 11 11
,而不是 11 12
;如果 auto
尚未刪除此引用,則會出現此情況。
const
限定符const
表示指針本身是個常量,底層const
表示指針所指的對象是一個常量。一般auto
會忽略掉頂層const
,同時底層const
則會保留下來,例如:
int i = 0;
const int ci = i, &cr = ci;
auto b = ci; // b 是一個整數(ci的頂層const特性被忽略掉)
auto c = cr; // c 是一個整數(cr是ci的別名,ci本身是一個頂層const)
auto d = &i; // d 是一個整型指針(整數的地址就是指向整數的指針)
auto e = &ci; // e 是一個指向整數常量的指針(對常量對象取地址是一種底層const)
如果希望推斷出的auto
類型是一個頂層const
,需要明確指出:
const auto f = ci; // ci 的推演類型是int,f是const int類型
還可以將引用的類型設置為auto
,此時原來的初始化規則仍然適用:
auto &g = ci; // g是一個整型常量引用,綁定到ci
auto &h = 42; // Error: 不能為非常量引用綁定字面值
const auto &j = 42; // OK: 可以為常量引用綁定字面值
切記,符號*
和&
只從屬於某個聲明,而非基本數據類型的一部分,因此初始值必須是同一類型:
auto k = ci, &l = i; // k是整數,l是整型引用
auto &m = ci, *p = &ci; // m是對整型常量的引用,p是指向整型常量的指針
auto &n = i, *p2 = &ci; // Error: i的類型是int,而&ci的類型是const int
附上更多示例代碼:
下面的聲明等效。在第一個語句中,將變量j
聲明為類型 int
。在第二個語句中,將變量 k
推導為類型 int
,因為初始化表達式 (0) 是整數
int j = 0; // Variable j is explicitly type int.
auto k = 0; // Variable k is implicitly type int because 0 is an integer.
以下聲明等效,但第二個聲明比第一個更簡單。使用 auto
關鍵字的最令人信服的一個原因是簡單
map>::iterator i = m.begin();
auto i = m.begin();
iter
和 elem
啟動循環時
#include
using namespace std;
int main()
{
deque dqDoubleData(10, 0.1);
for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end(); ++iter)
{ /* ... */ }
// prefer range-for loops with the following information in mind
// (this applies to any range-for with auto, not just deque)
for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples
{ /* ... */ }
for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-PLACE
{ /* ... */ }
for (const auto& elem : dqDoubleData) // observes elements IN-PLACE
{ /* ... */ }
}
new
運算符和指針聲明來聲明指針
double x = 12.34;
auto *y = new auto(x), **z = new auto(&x);
下一個代碼片段在每個聲明語句中聲明多個符號。請注意,每個語句中的所有符號將解析為同一類型。
auto x = 1, *y = &x, **z = &y; // Resolves to int.
auto a(2.01), *b (&a); // Resolves to double.
auto c = 'a', *d(&c); // Resolves to char.
auto m = 1, &n = m; // Resolves to int.
此代碼片段使用條件運算符 (?:
) 將變量 x
聲明為值為 200
的整數:
int v1 = 100, v2 = 200;
auto x = v1 > v2 ? v1 : v2;
下面的代碼片段將變量 x
初始化為類型 int
,將變量 y
初始化對類型 const int
的引用,將變量 fp
初始化為指向返回類型 int
的函數的指針。
int f(int x) { return x; }
int main()
{
auto x = f(0);
const auto & y = f(1);
int (*p)(int x);
p = f;
auto fp = p;
//...
}