天天看點

C++ 11 新特性: auto 和 decltype 差別和聯系

一. auto簡介

程式設計時候常常需要把表達式的值付給變量,需要在聲明變量的時候清楚的知道變量是什麼類型。然而做到這一點并非那麼容易(特别是模闆中),有時候根本做不到。為了解決這個問題,C++11新标準就引入了auto類型說明符,用它就能讓編譯器替我們去分析表達式所屬的類型。和原來那些隻對應某種特定的類型說明符(例如 int)不同。auto 讓編譯器通過初始值來進行類型推演。進而獲得定義變量的類型,是以說 auto 定義的變量必須有初始值。

    //由val_1 和val_2相加的結果可以推斷出item的類型

    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.

            使用auto也能在一個語句中聲明多個變量,因為一個聲明雨具隻能有一個基本資料類型,是以該雨具所有變量的初始基本資料類型都必須是一樣的。在這裡一定要差別資料類型和類型修飾符!!

    int i = 3;

    auto a = i,&b = i,*c = &i;//正确: a初始化為i的副本,b初始化為i的引用,c為i的指針.

    auto sz = 0, pi = 3.14;//錯誤,兩個變量的類型不一樣。

            編譯器推斷出來的auto類型有時候會跟初始值的類型并不完全一樣,編譯器會适當的改變結果類型使得其更符合初始化規則。

            首先,正如我們熟知的,使用引用其實是使用引用的對象,特别當引用被用作初始值的時候,真正參與初始化的其實是引用對象的值。此時編譯器以引用對象的類型作為auto的類型:

    int i = 0 ,&r = i;//定義一個整數i,并且定義r為i的應用.

    auto a = r; //這裡的a為為一個整數,其值跟此時的i一樣.

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

        int i = 0;

        const int ci = i, &cr = ci;  //ci 為整數常量,cr 為整數常量引用

        auto a = ci;     // a 為一個整數, 頂層const被忽略

        auto b = cr;     // b 為一個整數,頂層const被忽略

        auto c = &ci;    // c 為一個整數指針.

        auto d = &cr;    // d 為一個指向整數常量的指針(對常量對象區位址是那麼const會變成底層const)

            如果你希望推斷出auto類型是一個頂層的const,需要明确指出:

const auto f = ci;

            還可以将引用的類型設為auto,此時原來的初始化規則仍然适用(用于引用聲明的const都是底層const):

    auto &g = ci; //g是一個整數常量引用,綁定到ci。

    auto &h = 42; // 錯誤:非常量引用的初始值必須為左值。

    const auto &j = 42; //正确:常量引用可以綁定到字面值。

二. decltype簡介

            有的時候我們還會遇到這種情況,我們希望從表達式中推斷出要定義變量的類型,但卻不想用表達式的值去初始化變量。還有可能是函數的傳回類型為某表達式的的值類型。在這些時候auto顯得就無力了,是以C++11又引入了第二種類型說明符decltype,它的作用是選擇并傳回操作數的資料類型。在此過程中,編譯器隻是分析表達式并得到它的類型,卻不進行實際的計算表達式的值。

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

            在這裡編譯器并不實際調用f函數,而是分析f函數的傳回值作為sum的定義類型。

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

三. decltype 和 auto 差別

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

        const int ci = 42, &cj = ci;

        decltype(ci) x = 0;   // x 類型為const int

        auto z = ci;          // z 類型為int

        decltype(cj) y = x;   // y 類型為const int&

        auto h = cj;          // h 類型為int

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

        int i = 42, *p = &i, &r = i;

        decltype(i) x1 = 0;       //因為 i 為 int ,是以 x1 為int

        auto x2 = i;              //因為 i 為 int ,是以 x2 為int

        decltype(r) y1 = i;       //因為 r 為 int& ,是以 y1 為int&

        auto y2 = r;              //因為 r 為 int& ,但auto會忽略引用,是以 y2 為int

        decltype(r + 0) z1 = 0;   //因為 r + 0 為 int ,是以 z1 為int,

        auto z2 = r + 0;          //因為 r + 0 為 int ,是以 z2 為int,

        decltype(*p) h1 = i;      //這裡 h1 是int&, 原因後面講

        auto h2 = *p;             // h2 為 int.

           如果表達式的内容是解引用操作,則decltype将得到引用類型。正如我們所熟悉的那樣,解引用指針可以得到指針所指對象,而且還可以給這個對象指派。是以decltype(*p)的結果類型就是int&.

           decltype和auto還有一處重要的差別是,decltype的結果類型與表達形式密切相關。有一種情況需要特别注意:對于decltype 所用表達式來說,如果變量名加上一對括号,則得到的類型與不加上括号的時候可能不同。如果decltype使用的是一個不加括号的變量,那麼得到的結果就是這個變量的類型。但是如果給這個變量加上一個或多層括号,那麼編譯器會把這個變量當作一個表達式看待,變量是一個可以作為左值的特殊表達式,是以這樣的decltype就會傳回引用類型:

        int i = 42;

        //decltype(i)   int  類型

        //decltype((i)) int& 類型

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

    int main()

    {

        decltype(i = 41) x = i;

        auto y = i;

        auto& z = i;

        printf("i x y z 此時為: %d %d %d %d\n", i,x,y,z);

        i--;

        printf("i x y z 此時為: %d %d %d %d\n", i, x, y, z);

        x--;

        y--;

        z--;

        return 0;

    }

運作結果為:

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 以及引用 與非引用 的差别!!

————————————————

版權聲明:本文為部落客「YzlCoder」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

繼續閱讀