隨著程式越來越複雜,程式中用到的型別也越來越複雜,這種複雜性體現在兩個方面。一是一些型別難於「拼寫」,它們的名字既難記又容易寫錯,還無法明確體現其真實目的和含義。二是有時候根本搞不清到底需要的型別是什麼,程式設計師不得不回過頭去從程式的上下文中尋求幫助。
typedef來源於 C,可以給型別使用別名:
typedef int size; // size 就代表int
typedef double wage, *p; // wage代表double,而p代表double*
typedef double adouble[10]; //adouble代表double[10]
第一個很簡單,後面的麼看?把typedef
去掉看後面的宣告,後面的識別符號型別是什麼,那麼代表什麼,宣告可以千奇百怪,typedef
自然也千奇百怪。在新標準中,可以用using
來替代它:
using p = double*;
有一點要注意:用了這個東西,識別符號就是一個整體了,不能像define一樣做字串替換然後又拆開。比如:
typedef char * charp;
const charp cp = 0;
charp是一個整體,被const修飾。所以它實際是「常數指標」。要是拆開變成const char *
的話,就成為了「指向常數的指標」,這顯然不對。
程式設計時常常需要把表示式的值賦給變數,這就要求在宣告變數的時候清楚地知道表示式的型別。然而要做到這一點並非那麼容易,有時甚至根本做不到。為了解決這個問題,C++11新標準引入了auto
型別說明符,用它就能讓編譯器替我們去分析表示式所屬的型別。和原來那些只對應一種特定型別的說明符(比如 double
)不同,auto 讓編譯器通過初始值來推算變數的型別。顯然,auto定義的變數必須有初始值:
auto i = 3 + 2; //從右推左, auto填充為int
auto m = 9。0, *p = &m; // auto填充為double
auto a = 3, b = 2.0; // 不可以,只能填充一個值
vector<int> v{1, 2, 3, 4};
auto it = v.begin(); // 型別為vector<int>::iterator,避免冗長的宣告。
auto
是從右邊型別推左邊型別,並不是變數宣告時的型別。
int i = 0, &r = i;
auto a = r; //a是int,不是int&
auto &b = r; //參照需顯式指定
const int c = 0;
auto x = c; // 填充為int,右const被忽略
const auto y = c; // 右const要手動指定
auto p = &c; // 填充為const int *,左const會被保留
int ir[10];
auto x = ir; // 陣列名被轉化為指標,值int*
auto &x = ir; // 陣列名還是陣列,值為int[10]
auto也有助於提升程式的可拓展性,每個變數的型別都依賴其他變數,只需第一個宣告的變數,後面所有變數的型別同時也就更改了,很方便。
auto a = 3;
for (auto i(a); i < 12; i++)
...
將a = 3
改為a = 3ll
,則所有變數都被擴充套件為64位元型別。
受譚浩強影響,很多人覺得「陣列就是指標」。這種說法是錯誤的。陣列就是陣列啦,只是某些場合可以轉化成元素頭指標。C++ Primer裡提出一個有趣的例子:
int a[3][3] = {};
for (auto &row: a)
//for (auto row: a)
for (auto &col: row) cout << col << endl;
上面的程式碼可以正常執行,但是換成註釋語句後就不行了,原因在前面的範例程式碼裡已經提過了。auto &row: a
裡,row的型別是int[3]
,是可迭代的。但auto row: a
裡,它的型別成為了int*
,不可迭代,自然第二個for執行不了。陣列到指標是一種退化,因為只有頭地址而丟失了長度。
在更新的版本中,auto還可以用於形參型別和返回值:
auto triple_adder(auto &&a, auto &&b, auto &&c) {
return a + b + c;
}
main() {
cout << triple_adder(1, 2, 3.2) << endl; //6.2
cout << triple_adder(string("he"), string("ll"), string("oo")) << endl; //helloo
}
將引數宣告為auto
,作用與模板完全相同(但更簡潔),會根據型別生成多個函數。而返回值設為 auto
,就可以根據return語句的型別自動生成返回型別。不過auto只是代表「自動推斷一種型別」。C++的函數返回值只能有一種型別。如果多處return型別不一致,推斷失敗就會報錯。
decltype
是和 auto 一起推出的,不過沒那麼簡潔,用的不多。decltyle是完整嚴格的型別推斷。
decltype(3) i = 12; // 3的型別是int,所以是int
decltype(f()) j = 0; // f的返回型別決定j的型別,但是並不會執行f
與auto
不同,decltype
的規則為「括號裡面是什麼就是什麼」:
const int a = 3;
decltype(a) ca = a; //ca 是const int
int b = 5, &rb = b;
decltype(b) rb = a; //rb 是int&
decltype(b+0) rrb = 1; //是int
int ar[10];
decltype(ar) p; //是int[10]