C++11新特性之auto

    1. auto的使用 
      c++11引入了auto類型說明符,auto讓編譯器經過初始值來推算變量的類型,因此auto定義的變量必須有初始值。 
      使用auto也能在一條語句中聲明多個變量,由於一條聲明語句只能有一個基本數據類型,因此該語句中全部變量的初始基本數據類型都必須同樣: 
    2. eg: auto i=0,*p=& i; //正確 auto sz=0,pi=3.14;//錯誤,sz和pi的類型不同。 範圍for循環,遍歷給定序列中的每一個元素並對序列中的每一個值執行某種操做。

    3. for(declaration:expression)
      1. statement

    4. expression 部分是一個對象,用於表示一個序列,declaration部分負責定義一個變量,該變量被用於訪問序列中的基礎元素,每次迭代declaration部分的變量會被初始化爲expression部分的下一個元素值。

      範圍for循環有兩種用法:能夠遍歷字符串,數組,map,vector等容器。
      java

      1. string s("hello,world");
        decltype(s.size()) punct_cnt=0;//decltype也是c++11特性,用於選擇和返回操做數的數據類型。
        for(auto c:s)//對於s中的每一個字符
            if(ispunct(c))
                ++punct_cnt;
      2. string s("hello,world");
        for(auto &c:s);//對於s中的每一個字符,c是一個引用,賦值語句將會改變s中字符的值
            c=toupper(c);
        cout<<s<<endl;

         

    5.   

      正文c++

      前言

      本文的內容已經不新鮮了。關於auto,翻來覆去被人知道的都是這些東西,本文並無提出新穎的auto用法。
      本人原是痛恨博客一篇篇都是copy而來缺少新意的探索,固然,本文不是copy而來,但發佈這樣一篇你們皆知的文章內心甚是惶恐。
      本文對auto的內容加以整理,權當是本身的複習筆記了。express

       

      C++98 auto

      早在C++98標準中就存在了auto關鍵字,那時的auto用於聲明變量爲自動變量,自動變量意爲擁有自動的生命期,這是多餘的,由於就算不使用auto聲明,變量依舊擁有自動的生命期:編程

      int a =10 ; //擁有自動生命期 auto int b = 20 ;//擁有自動生命期 static int c = 30 ;//延長了生命期

      C++98中的auto多餘且極少使用,C++11已經刪除了這一用法,取而代之的是全新的auto:變量的自動類型推斷。數組

      C++11 auto

      auto能夠在聲明變量的時候根據變量初始值的類型自動爲此變量選擇匹配的類型,相似的關鍵字還有decltype。舉個例子:ide

      int a = 10; auto au_a = a;//自動類型推斷,au_a爲int類型 cout << typeid(au_a).name() << endl;

      typeid運算符能夠輸出變量的類型。程序的運行結果輸出了函數

      intui

      這種用法就相似於C#或java中的var關鍵字。auto的自動類型推斷髮生在編譯期,因此使用auto並不會形成程序運行時效率的下降。而是否會形成編譯期的時間消耗,我認爲是不會的,在未使用auto時,編譯器也須要得知右操做數的類型,再與左操做數的類型進行比較,檢查是否能夠發生相應的轉化,是否須要進行隱式類型轉換。spa

       

      auto的用法

      上面舉的這個例子很簡單,在真正編程的時候也不建議這樣來使用auto,直接寫出變量的類型更加清晰易懂。下面列舉auto關鍵字的正確用法。指針

      用於代替冗長複雜、變量使用範圍專注的變量聲明。

      想象一下在沒有auto的時候,咱們操做標準庫時常常須要這樣:

      #include<string> #include<vector> int main() { std::vector<std::string> vs; for (std::vector<std::string>::iterator i = vs.begin(); i != vs.end(); i++) { //... } }

      這樣看代碼寫代碼實在煩得很。有人可能會說爲什麼不直接使用using namespace std,這樣代碼能夠短一點。實際上這不是該建議的方法(C++Primer對此有相關敘述)。使用auto能簡化代碼:

      #include<string> #include<vector> int main() { std::vector<std::string> vs; for (auto i = vs.begin(); i != vs.end(); i++) { //.. } }

      for循環中的i將在編譯時自動推導其類型,而不用咱們顯式去定義那長長的一串。

      在定義模板函數時,用於聲明依賴模板參數的變量類型。

      template <typename _Tx,typename _Ty> void Multiply(_Tx x, _Ty y) { auto v = x*y; std::cout << v; }

      若不使用auto變量來聲明v,那這個函數就難定義啦,不到編譯的時候,誰知道x*y的真正類型是什麼呢?

      模板函數依賴於模板參數的返回值

      template <typename _Tx, typename _Ty> auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty) { return x*y; }

      當模板函數的返回值依賴於模板的參數時,咱們依舊沒法在編譯代碼前肯定模板參數的類型,故也無從知道返回值的類型,這時咱們可使用auto。格式如上所示。
      decltype操做符用於查詢表達式的數據類型,也是C++11標準引入的新的運算符,其目的也是解決泛型編程中有些類型由模板參數決定,而難以表示它的問題。
      auto在這裏的做用也稱爲返回值佔位,它只是爲函數返回值佔了一個位置,真正的返回值是後面的decltype(_Tx*_Ty)。爲什麼要將返回值後置呢?若是沒有後置,則函數聲明時爲:

      decltype(_Tx*_Ty)multiply(_Tx x, _Ty y)

      而此時_Tx,_Ty還沒聲明呢,編譯沒法經過。

       

      注意事項

      • auto 變量必須在定義時初始化,這相似於const關鍵字。
      • 定義在一個auto序列的變量必須始終推導成同一類型。例如:

        auto a4 = 10, a5 = 20, a6 = 30;//正確 auto b4 = 10, b5 = 20.0, b6 = 'a';//錯誤,沒有推導爲同一類型
        使用auto關鍵字作類型自動推導時,依次施加一下規則:
      • 若是初始化表達式是引用,則去除引用語義。

        int a = 10; int &b = a; auto c = b;//c的類型爲int而非int&(去除引用) auto &d = b;//此時c的類型才爲int& c = 100;//a =10; d = 100;//a =100;
      • 若是初始化表達式爲const或volatile(或者二者兼有),則除去const/volatile語義。

        const int a1 = 10; auto b1= a1; //b1的類型爲int而非const int(去除const) const auto c1 = a1;//此時c1的類型爲const int b1 = 100;//合法 c1 = 100;//非法
      • 若是auto關鍵字帶上&號,則不去除const語意。

        const int a2 = 10; auto &b2 = a2;//由於auto帶上&,故不去除const,b2類型爲const int b2 = 10; //非法
        這是由於如何去掉了const,則b2爲a2的非const引用,經過b2能夠改變a2的值,則顯然是不合理的。
      • 初始化表達式爲數組時,auto關鍵字推導類型爲指針。

        int a3[3] = { 1, 2, 3 }; auto b3 = a3; cout << typeid(b3).name() << endl;

        程序將輸出

        int *

      • 若表達式爲數組且auto帶上&,則推導類型爲數組類型。

        int a7[3] = { 1, 2, 3 }; auto & b7 = a7; cout << typeid(b7).name() << endl;

        程序輸出

        int [3]

      • 函數或者模板參數不能被聲明爲auto

        void func(auto a) //錯誤 { //... }
      • 時刻要注意auto並非一個真正的類型。
        auto僅僅是一個佔位符,它並非一個真正的類型,不能使用一些以類型爲操做數的操做符,如sizeof或者typeid。

        cout << sizeof(auto) << endl;//錯誤 cout << typeid(auto).name() << endl;//錯誤
相關文章
相關標籤/搜索