C++ 處理類型名(typedef,auto和decltype)
- 2022 年 7 月 26 日
- 筆記
隨著程式越來越複雜,程式中用到的類型也越來越複雜,這種複雜性體現在兩個方面。一是一些類型難於「拼寫」,它們的名字既難記又容易寫錯,還無法明確體現其真實目的和含義。二是有時候根本搞不清到底需要的類型是什麼,程式設計師不得不回過頭去從程式的上下文中尋求幫助。
typedef
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 *的話,就成為了「指向常量的指針」,這顯然不對。
auto
編程時常常需要把表達式的值賦給變數,這就要求在聲明變數的時候清楚地知道表達式的類型。然而要做到這一點並非那麼容易,有時甚至根本做不到。為了解決這個問題,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位類型。
auto將數組轉為指針大不相同
受譚浩強影響,很多人覺得「數組就是指針」。這種說法是錯誤的。數組就是數組啦,只是某些場合可以轉化成元素頭指針。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還可以用於形參類型和返回值:
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
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]

