C++拾趣——C++11的语法糖auto
? ? ? ? C++是一種強類型的語言,比如變量a,如果聲明它是整型,則之后只能將它作為整型來用。這和其他弱類型的語言有很大的區別,比如python中,我們可以讓a在第一行是個整型,第三行是一個字符串。(轉載請指明出于breaksoftware的csdn博客)
a = 3
print a
a = "3"
print a
? ? ? ? C++代碼在聲明一個變量時就已經明確指定了它的類型。這樣在編譯器給它分配內存時,就知道分配出什么多大的空間。從這個角度來說,C++的語法是站在編譯器實現的角度設計的。然而隨著編程技術的普及,大家都希望代碼寫出來是給人看的,而不是給機器看的。但是在C++代碼的一些場景下,有一定基礎的程序員都可以通過右值推導出左值變量類型時,編譯器還是要求寫明類型,這無疑加重了程序員的負擔。比如下面的代碼
std::vector<int> vec_int;
……
std::vector<int>::iterator iter = vec_int.begin();
? ? ? ? 如果不看變量iter的類型聲明,我們也可以通過vector的begin()函數返回值類型推導出變量的類型。這樣的推導編譯器也完全可以完成。但是在C++11之前的標準中,我們也只能這種笨拙的方式去聲明。因為老的標準沒要求編譯器完成這樣的工作,而且即使各大編譯器廠商“超前”的完成了,也沒有一種統一的途徑可以表達出來。
? ? ? ? 于是在C++11的標準中引入了auto關鍵字,它讓上述類型推導通過統一的標準表達出來。我們可以使用auto去聲明一個變量,但是這并不意味著C++增加了一個auto類型——一個可以表示任意類型的類型。因為強類型特性是不會變的,變的只是編譯器,它變的更加高級——推導出確定的類型。這兒特別需要指出的是:auto關鍵字并不是在預編譯過程中被替換成確定類型的。大家可以開啟VS2017的“生成預編譯文件”選項來驗證這點。
std::vector<int> vec_int;
……
auto iter = vec_int.begin();
? ? ? ? 上述代碼中auto便將std::vector<int>::iterator替換了,這在一定程度上降低了程序員的負擔。
? ? ? ? 在C++11標準推出之前,我們可以使用別名來減少負擔。比如會在一個共有的頭文件中做如下定義:
typedef std::vector<int> VecInt;
typedef VecInt::iterator VecIntIter;
typedef VecInt::const_iterator VecIntCIter;
? ? ? ? 然后在代碼中使用上述別名
VecInt vec_int;
……
VecIntIter = vec_int.begin();
? ? ? ? 當然這不失為一種方法,但是這就要求每定義一個容器,都要別名它相應的迭代器。auto的出現幫我們省掉了這些繁瑣且意義不大的書寫。
? ? ? ? auto是個非常好的設計,但是也不可毫無原則的濫用。
? ? ? ? 作為C++標準,要求auto變量在聲明時要被初始化。該初始化操作其實就是指定了其真實類型。一般我們可以使用表達式來初始化一個變量,也可以使用字面值、字面量、常量或者一個明確類型的變量。不管我們使用哪種方式,都希望auto的推導不會產生“歧義”。比如
auto i = 0x01;
? ? ? ? 在VS2017中,我們將其類型打印出來(typeid(i).name())是int。那可能會問,為什么不是unsigned int,long等呢?現在我們換個字面值(8個f)
auto i = 0xffffffff;
? ? ? ? 此時,編譯器就會認為類型為unsigned int。我們再修改字面值(15個f,1一個0)
auto i = 0x0fffffffffffffff;
? ? ? ? 編譯器推導出的類型是__int64。我們再將類型改成(16個f)
auto i = 0xffffffffffffffff;
? ? ? ? 編譯器推導出的類型是unsigned __int64。
? ? ? ? 可以見得,在使用字面值或者字面量初始化auto變量時往往會產生“誤解”。所以一旦我們自己對推導產生疑問時,最好使用明確的類型來定義變量。
? ? ? ? 其次,不要寄希望于編譯器可以通過構造函數隱式轉換推導類型。比如下面的初始化方式,我們可能會認為變量類型是std::string。
auto i = "which type?";
? ? ? ? 但是真實的推導類型是char const *。為什么呢?因為當我們使用
std::string i = "which type?";
? ? ? ? 賦值符將會觸發basic_string類構造函數隱式轉換(《C++拾趣——類構造函數的隱式轉換》)
basic_string(_In_z_ const _Elem * const _Ptr): _Mybase(){ // construct from [_Ptr, <null>)_Tidy_init();assign(_Ptr);}
? ? ? ? 這是由于左值已經指定類型才會發生的。所以如果使用auto定義一個字面量,其類型是char const *。鑒于理解這樣的過程需要掌握一定的C++基礎知識,所以我也不建議在這個場景下使用auto去定義變量。
? ? ? ? 綜上所述,除了在模板中必要的地方使用auto外,其他地方都需要可以從右值一眼看出類型,否則就會產生理解上的歧義或者困擾。
總結
以上是生活随笔為你收集整理的C++拾趣——C++11的语法糖auto的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下HOOK动态链接库中API的
- 下一篇: 绑定CPU逻辑核心的利器——taskse