C++11新特性之decltype關鍵字的使用


一.decltype關鍵字介紹

decltype關鍵字與auto關鍵字相似,但又有不同之處;auto關鍵字是在編譯時通過已經初始化的變量來確定auto所代表的類型。換句話說,auto修飾的表達式必須是已經初始化的變量;那么如果我們只是想得到此變量的類型,那又該如何做呢?這個時候就輪到decltype出場了,decltype關鍵字也是用來在編譯時推導出一個表達式的類型,但此表達式初始化與否,在編譯器都沒有多大的影響。

下面是使用關鍵字decltype關鍵字的示例:

#include <iostream>
using namespace std;

int main()
{
    int x = 0;
    decltype(x) y = 1;  //y -> int
    cout << y << endl;
    decltype(x + y) z = 2; //z -> int
    cout << z << endl;

    const int& i = x;
    decltype(i) j = y;  //j -> const int &

    cout << j << endl;

    const decltype(z) *p = &z;  //*p -> const int
    decltype(z) *pi = &z;       //*pi -> int, pi->int*
    decltype(pi) *pp = &pi;     //*pp -> int*, pp->int**

    cout << pp << endl;         //打印結果:0x61fe80
    cout << *pp << endl;        //打印結果:0x61fe84
    cout << **pp << endl;       //打印結果:2

    return 0;
}

A.y和z的結果表明decltype可以根據表達式直接推導出變量的類型,這個功能和auto很像,但又有所不同,auto只能根據變量的初始化表達式推導出變量應該具有的類型,如果想要通過某個表達式得到類型,但又不希望新變量和這個表達式具有同樣的值,那么這個時候auto就不太適用了。

B.j的結果表明decltype通過表達式得到的類型,可以保留表達式的引用及const限定符,decltype能夠精確地推導出表達式定義本身的類型,不會像auto那樣在某些情況下舍棄掉引用和cv限定符。

C.p、pi的結果表明decltype可以像auto一樣,加上引用和指針,以及cv限定符。

D.pp的推導說明,當表達式是一個指針的時候,decltype仍然能夠推導出表達式的實際類型(指針類型),之后結合pp定義時的指針標記,得到的pp是一個二維指針類型

二.decltype的推導規則

decltyp(exp)的推導規則如下所示:

(1).標識符表達式和類訪問表達式。

(2).函數調用(非標識符表達式,也非類訪問表達式)。

(3).帶括號的表達式和加法運算表達式(其他情況)。

先來說第一種情況:

#include <iostream>
using namespace std;

class Test
{
public:
    Test() {}

public:
    static const int nNumber = 0;
    int x;
};

int main()
{

    //類訪問表達式
    decltype(Test::nNumber) c = 10;
    Test test;
    decltype(test.x) d = 20;
    cout << c << "," << d <<endl;

    //標識符表達式
    int y = 20;
    decltype(y) z = 30;
   return 0;
}

第二種情況:函數調用

#include <iostream>

using namespace std;

class Test
{
public:
    Test() {}

public:
    int m_nNum = -10;
};

int Test_Int();             //純右值
int& Test_Int_One();        //左值

const int Test_Cint();      //純右值
const int& Test_Cint_One(); //左值

const Test Test_Class();    //純右值

int main()
{
    int x = 10;

    decltype(Test_Int()) a1 = x;        //a1->int
    cout << a1 << endl;

    decltype(Test_Cint_One()) a2 = x;   //a2->int&
    int y = a2;
    cout << y << endl;
    cout << a2 << endl;

    decltype(Test_Cint()) b1 = x;       //b1->const int
    b1 = 20;
    cout << b1 << endl;

    decltype(Test_Cint_One()) b2 = x;   //b2->const& int
    //b2 = 30;                            //error:b2只是一個只讀引用,不可再為其賦值
    cout << b2 << endl;

    decltype(Test_Class()) c1 = Test();
    cout << c1.m_nNum << endl;

    return 0;
}

能夠看出按照規則2推導decltype的結果和函數的返回值類型保持一致,但需要注意的是b1是int而不是const int,這是因為函數返回的int是一個純右值,對於純右值而言,只有類類型可以攜帶cv限定符,除此之外的一般都會忽略掉cv限定符;因此decltype推導出來的b1是一個int類型,而c1推導出的類型是const Test。

第三種:帶括號的表達式和加法運算表達式

#include <iostream>

using namespace std;

class Test
{
public:
    Test() {}

public:
    static const int nNum = -10;
    int x = 0;
};


int main()
{
    const Test test = Test();

    decltype(test.x) a = 0;     //a->int
    decltype((test.x)) b = a;   //b->const int&
    b = 10;                     //error:b為只讀引用
    cout << b << endl;

    int m =0,n=0;
    decltype(m + n) c = 10;     //c->int
    decltype(m += n) d = c;      //d ->int &


    return 0;
}

a和b的結果:僅僅多加了一對括號,它們得到的類型卻不是相同的。

a的結果很明顯,根據推導規則1,a的類型就是test.x的定義類型。

b的結果並不適用與推導規則1和推導規則2,根據test.x是一個左值,可知括號表達式也是一個左值,因此可以根據推導規則3,知道decltype的結果將是一個左值引用;因為test的定義時const Test,所以說foo.x是一個const int類型左值,因此decltype的推導結果是const int&.

同樣的,m+n返回一個右值,decltype的結果為int。最后,m+=n返回一個左值,根據推導規則3,decltype的結果為int&.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM