自動推導基礎
auto
關鍵字的推導過程完全處於 compile-time,所以並不會影響程式效能。應該放心大膽的使用。
cpp
auto i = 1; // i will become int auto l = 1LL; // l will become long long auto d = 1.0; // d will become double auto f = 1.0f; // f will become float std::vector<int> ivec{1, 2, 3, 4, 5}; for (auto i : ivec) std::cout << i << " "; // 1 2 3 4 5
這樣使用 auto
可能會要求你記住一些字面量的型別標識:
- 前置
標識 含義 型別 u Unicode 16 character char16_t
U Unicode 32 character char32_t
L wide character wchar_t
u8 utf-8(string literals only) char
可能經常用 VS 和 Windows API 的人比較熟悉 L
,用來標識寬字元。(不得不說,這一點,微軟還是挺超前的)
- 後置
字面量 標識 型別 整型 u / U
unsigned
整型 l / L
long
整型 ll / LL
long long
浮點 f / F
float
浮點 l / L
long double
這些與 C 語言一脈相承,應該比較熟悉了。
特殊情況
cpp
auto str = "hello";
請問,str
是什麼型別?最近才發現,很多初學者竟然想當然的認為str
是std::string
.(尤其是沒有 C 語言基礎的)
實際上,str
此時是 const char *
.
所以當你對 str
進行 range for 的時候,就會傻眼。
cpp
for (auto c : str) { // error! str 沒有 begin() 和 end() //... }
上述情況應該如何避免?
cpp
auto& str = "hello";
請問,str
是什麼型別?
是 const char[6]
. 這是一個陣列了,那麼 range for 當然沒問題了。
還有別的方法嗎?
當然,右值引用不是吃閒飯的:
cpp
auto&& str = "hello";
range for 照樣沒問題。請問 str
此刻是什麼型別?
是 const char(&)[6]
.
這都是非常基礎的內容,你都清楚嗎?
另外補充一個:
cpp
auto il = {1, 2, 3, 4, 5, 6};
不要覺得 il
會是 std::array
或 普通陣列,甚至是 std::vector
. 它的型別應該是: std::initializer_list
。
什麼時候該用 auto
- 一種說法是:能用
auto
的地方都該用。(尤其是受到python
等動態語言影響的人)。 - 另一種說法:
auto
會讓程式碼變得不直觀,在一個強型別的語言中,會搞得人莫名其妙。
經過一段時間的瘋狂實踐。我覺得上述兩種觀點都有失偏頗。
其實,開始我是支援第一種觀點的,於是開始大量使用 auto
, 直到有一天 review 自己的程式碼時。竟然發現很多變數完全看不出是什麼型別。如:
cpp
auto foo = bla(); // 請問 foo 你能看出型別來嗎?
這就傻眼了。違反了最基本的程式設計原則——“清晰易懂,方便擴充套件”,看都看迷糊了,擴充套件毛啊。
但有些情況,其實極大程度上的簡化了程式,使之簡潔明瞭:
cpp
auto foo = std::make_shared<Foo>(); // 一看就知道型別 for (auto iter = vec.cbegin(); iter != vec.cend(); ++iter) {} // 一看就知道型別
上述兩種情況下,把 auto
擴充套件開來,會顯得重複、冗長。
這兩個例子,應該能夠說明使用 auto
的那條 “金線” 在哪了。我們的目的不是為了用而用,而是儘可能的讓自己的程式,易於維護,保持新鮮。
故,不要濫用,不要避諱。