c++11 auto 與 decltype 詳解

一. auto簡介c++

編程時候經常須要把表達式的值付給變量,須要在聲明變量的時候清楚的知道變量是什麼類型。然而作到這一點並不是那麼容易(特別是模板中),有時候根本作不到。爲了解決這個問題,C++11新標準就引入了auto類型說明符,用它就能讓編譯器替咱們去分析表達式所屬的類型。和原來那些只對應某種特定的類型說明符(例如 int)不一樣。auto 讓編譯器經過初始值來進行類型推演。從而得到定義變量的類型,因此說 auto 定義的變量必須有初始值。編程

 

[cpp] view plain copy函數

 

  1. //由val_1 和val_2相加的結果能夠推斷出item的類型  
  2. auto item = val_1 + val_2;//item 類型初始化爲val_1 + val_2相加後的類型,值爲val_1+val_2相加的值。  


 

 

    這裏的 item 的類型是編譯器在編譯的過程當中經過val_1和val_2的類型相加後推算出來的。假如是val_1(int) + val_2(double),那麼item的類型就是double..net

            使用auto也能在一個語句中聲明多個變量,由於一個聲明雨具只能有一個基本數據類型,因此該雨具全部變量的初始基本數據類型都必須是同樣的。在這裏必定要區別數據類型和類型修飾符!!指針

 

[cpp] view plain copyc++11

 

  1. int i = 3;  
  2. auto a = i,&b = i,*c = &i;//正確: a初始化爲i的副本,b初始化爲i的引用,c爲i的指針.  
  3. auto sz = 0, pi = 3.14;//錯誤,兩個變量的類型不同。  


            編譯器推斷出來的auto類型有時候會跟初始值的類型並不徹底同樣,編譯器會適當的改變結果類型使得其更符合初始化規則。對象

 

            首先,正如咱們熟知的,使用引用實際上是使用引用的對象,特別當引用被用做初始值的時候,真正參與初始化的實際上是引用對象的值。此時編譯器以引用對象的類型做爲auto的類型:blog

 

[cpp] view plain copyci

 

  1. int i = 0 ,&r = i;//定義一個整數i,而且定義r爲i的應用.  
  2. auto a = r; //這裏的a爲爲一個整數,其值跟此時的i同樣.  


            由此能夠看出auto會忽略引用,其次,auto通常會忽略掉頂層const,但底層const會被保留下來,好比當初始值是一個指向常量的指針時:get

 

 

[cpp] view plain copy

 

  1. int i = 0;  
  2. const int ci = i, &cr = ci;  //ci 爲整數常量,cr 爲整數常量引用   
  3. auto a = ci;     // a 爲一個整數, 頂層const被忽略  
  4. auto b = cr;     // b 爲一個整數,頂層const被忽略  
  5. auto c = &ci;    // c 爲一個整數指針.  
  6. auto d = &cr;    // d 爲一個指向整數常量的指針(對常量對象區地址是那麼const會變成底層const)  


            若是你但願推斷出auto類型是一個頂層的const,須要明確指出:

 

 

[cpp] view plain copy

 

  1. const auto f = ci;  


            還能夠將引用的類型設爲auto,此時原來的初始化規則仍然適用(用於引用聲明的const都是底層const):

 

 

[cpp] view plain copy

 

  1. auto &g = ci; //g是一個整數常量引用,綁定到ci。  
  2. auto &h = 42; // 錯誤:很是量引用的初始值必須爲左值。  
  3. const auto &j = 42; //正確:常量引用能夠綁定到字面值。   


 

 

二. decltype簡介

 

            有的時候咱們還會遇到這種狀況,咱們但願從表達式中推斷出要定義變量的類型,但卻不想用表達式的值去初始化變量。還有多是函數的返回類型爲某表達式的的值類型。在這些時候auto顯得就無力了,因此C++11又引入了第二種類型說明符decltype,它的做用是選擇並返回操做數的數據類型。在此過程當中,編譯器只是分析表達式並獲得它的類型,卻不進行實際的計算表達式的值。

 

[cpp] view plain copy

 

  1. decltype(f()) sum = x;// sum的類型就是函數f的返回值類型。  

          

 

            在這裏編譯器並不實際調用f函數,而是分析f函數的返回值做爲sum的定義類型。

            基本上decltype的做用和auto很類似,就不一一列舉了。對於decltype還有一個用途就是在c++11引入的後置返回類型。

 

三. decltype 和 auto 區別

 

            decltype在處理頂層const和引用的方式與auto有些許不一樣,若是decltype使用的表達式是一個變量,則decltype返回該變量的類型(包括頂層const和引用在內)。

 

[cpp] view plain copy

 

  1. const int ci = 42, &cj = ci;  
  2.   
  3. decltype(ci) x = 0;   // x 類型爲const int  
  4. auto z = ci;          // z 類型爲int  
  5.   
  6. decltype(cj) y = x;   // y 類型爲const int&  
  7. auto h = cj;          // h 類型爲int  


           decltype還有一些值得注意的地方,咱們先來看看下面這段代碼:

 

 

[cpp] view plain copy

 

  1. int i = 42, *p = &i, &r = i;  
  2.   
  3. decltype(i) x1 = 0;       //由於 i 爲 int ,因此 x1 爲int  
  4. auto x2 = i;              //由於 i 爲 int ,因此 x2 爲int  
  5.   
  6. decltype(r) y1 = i;       //由於 r 爲 int& ,因此 y1 爲int&  
  7. auto y2 = r;              //由於 r 爲 int& ,但auto會忽略引用,因此 y2 爲int  
  8.   
  9. decltype(r + 0) z1 = 0;   //由於 r + 0 爲 int ,因此 z1 爲int,  
  10. auto z2 = r + 0;          //由於 r + 0 爲 int ,因此 z2 爲int,  
  11.   
  12. decltype(*p) h1 = i;      //這裏 h1 是int&, 緣由後面講  
  13. auto h2 = *p;             // h2 爲 int.  


           若是表達式的內容是解引用操做,則decltype將獲得引用類型。正如咱們所熟悉的那樣,解引用指針能夠獲得指針所指對象,並且還能夠給這個對象賦值。所以decltype(*p)的結果類型就是int&.

 

           decltype和auto還有一處重要的區別是,decltype的結果類型與表達形式密切相關。有一種狀況須要特別注意:對於decltype 所用表達式來講,若是變量名加上一對括號,則獲得的類型與不加上括號的時候可能不一樣。若是decltype使用的是一個不加括號的變量,那麼獲得的結果就是這個變量的類型。可是若是給這個變量加上一個或多層括號,那麼編譯器會把這個變量看成一個表達式看待,變量是一個能夠做爲左值的特殊表達式,因此這樣的decltype就會返回引用類型:

 

[cpp] view plain copy

 

  1. int i = 42;  
  2.   
  3. //decltype(i)   int  類型  
  4. //decltype((i)) int& 類型  

  這裏再指出一個須要注意的地方就是 = 賦值運算符返回的是左值的引用。換句話意思就是說 decltype(i = b)  返回類型爲 i 類型的引用。仔細看下面這段代碼:

 

[cpp] view plain copy

  1. int main()  
  2. {  
  3.     int i = 42;  
  4.   
  5.     decltype(i = 41) x = i;  
  6.   
  7.     auto y = i;  
  8.   
  9.     auto& z = i;  
  10.   
  11.     printf("i x y z 此時爲: %d %d %d %d\n", i,x,y,z);  
  12.   
  13.     i--;  
  14.   
  15.     printf("i x y z 此時爲: %d %d %d %d\n", i, x, y, z);  
  16.   
  17.     x--;  
  18.   
  19.     printf("i x y z 此時爲: %d %d %d %d\n", i, x, y, z);  
  20.   
  21.     y--;  
  22.   
  23.     printf("i x y z 此時爲: %d %d %d %d\n", i, x, y, z);  
  24.   
  25.     z--;  
  26.   
  27.     printf("i x y z 此時爲: %d %d %d %d\n", i, x, y, z);  
  28.   
  29.     return 0;  
  30. }  

運行結果爲:

i x y z 此時爲: 42 42 42 42
i x y z 此時爲: 41 41 42 41
i x y z 此時爲: 40 40 42 40
i x y z 此時爲: 40 40 41 40
i x y z 此時爲: 39 39 41 39   
           由上面的代碼和運行結果能夠看出來,1.decltype(i = 41)中的賦值語句並無真正的運行。2. decltype(i = 41)返回的實際上是int&,也就是說x 實際上是 i 的引用。

瞭解了auto 和 decltype後,之後在使用的過程當中必定要分清二者的區別,防止在定義的時候產生const 與非const 以及引用 非引用 的差異!!

相關文章
相關標籤/搜索