C++11新標准:constexpr關鍵字


一、constexpr意義

  將變量聲明為constexpr類型以便由編譯器來驗證變量是否是一個常量表達式(不會改變,在編譯過程中就能得到計算結果的表達式)。是一種比const更強的約束,這樣可以得到更好的效率和安全性。

二、constexpr用法

  1.修飾函數

/*1.如果size在編譯時能確定,那么返回值就可以是constexpr,編譯通過*/
constexpr int getSizeA(int size)
{
    return 4*size;
}
/*2.編譯通過,有告警:在constexpr中定義變量*/
constexpr int getSizeB(int size)
{
    int index = 0;
    return 4;
}
/*3.編譯通過,有告警:在constexpr中定義變量(這個有點迷糊)*/
constexpr int getSizeC(int size)
{
    constexpr int index = 0;
    return 4;
}
/*4.編譯通過,有告警:使用了if語句(使用switch也會告警)*/
constexpr int getSizeD(int size)
{
    if(0)
    {}
    return 4;
}
/*5.定義變量並且沒有初始化,編譯不過*/
constexpr int getSizeE(int size)
{
    int index;
    return 4;
}
/*6.rand()為運行期函數,不能在編譯期確定,編譯不過*/
constexpr int getSizeF(int size)
{
    return 4*rand();
}
/*7.使用了for,編譯不過*/
constexpr int getSizeG(int size)
{
    for(;0;)
    {}
    return 4*rand();
}

  總結:constexpr修飾的函數,不能依賴任何運行期的信息,不要定義任何變量常量,並且必須盡量簡單,要不就會編譯不過或告警(坑)。

   2.修飾類型

    int tempA;
    cin>>tempA;
    
    const int ctempA = 4;
    const int ctempB = tempA;
    /*1.可以再編譯器確定,編譯通過*/
    constexpr int conexprA = 4;
    constexpr int conexprB = conexprA + 1;
    constexpr int conexprC = getSizeA(conexprA);
    constexpr int conexprD = ctempA;
    /*2.不能在編譯期決定,編譯不過*/
    constexpr int conexprE = tempA;
    constexpr int conexprF = ctempB; 

  總結:constexpr修飾的常量必須在編譯期確定值,上面的例子也體現出了和const之間的差別。const既可以在編譯期確定如ctempA,也可以在運行期確定如ctempB,使用范圍更廣。還有一點constexpr只能修飾字面值類型如算數類型、引用類型、指針以及后面介紹的字面值常量類。

  3.修飾指針

int g_tempA = 4;
const int g_conTempA = 4;
constexpr int g_conexprTempA = 4;

int main(void)
{
    int tempA = 4;
    const int conTempA = 4;
    constexpr int conexprTempA = 4;
    
    /*1.正常運行,編譯通過*/
    const int *conptrA = &tempA;
    const int *conptrB = &conTempA;
    const int *conptrC = &conexprTempA;
    /*2.局部變量的地址要運行時才能確認,故不能在編譯期決定,編譯不過*/
    constexpr int *conexprPtrA = &tempA;
    constexpr int *conexprPtrB = &conTempA
    constexpr int *conexprPtrC = &conexprTempA;
    /*3.第一個通過,后面兩個不過,因為constexpr int *所限定的是指針是常量,故不能將常量的地址賦給頂層const*/
    constexpr int *conexprPtrD = &g_tempA;
    constexpr int *conexprPtrE = &g_conTempA
    constexpr int *conexprPtrF = &g_conexprTempA;
    /*4.局部變量的地址要運行時才能確認,故不能在編譯期決定,編譯不過*/
    constexpr const int *conexprConPtrA = &tempA;
    constexpr const int *conexprConPtrB = &conTempA;
    constexpr const int *conexprConPtrC = &conexprTempA;
    /*5.正常運行,編譯通過*/
    constexpr const int *conexprConPtrD = &g_tempA;
    constexpr const int *conexprConPtrE = &g_conTempA;
    constexpr const int *conexprConPtrF = &g_conexprTempA;

    return 0;
}

  總結:constexpr指針不能用局部變量賦值,const指針可以;constexpr指針里是頂層const,即指針是常量,而不是所指向的類型是常量,如果要指向的類型也為常量,要用constexpr const來修飾。

4.修飾引用

int g_tempA = 4;
const int g_conTempA = 4;
constexpr int g_conexprTempA = 4;

int main(void)
{
    int tempA = 4;
    const int conTempA = 4;
    constexpr int conexprTempA = 4;
    /*1.正常運行,編譯通過*/
    const int &conptrA = tempA;
    const int &conptrB = conTempA;
    const int &conptrC = conexprTempA;
    /*2.有兩個問題:一是引用到局部變量,不能再編譯器確定;二是conexprPtrB和conexprPtrC應該為constexpr const類型,編譯不過*/
    constexpr int &conexprPtrA = tempA;
    constexpr int &conexprPtrB = conTempA 
    constexpr int &conexprPtrC = conexprTempA;
    /*3.第一個編譯通過,后兩個不通過,原因是因為conexprPtrE和conexprPtrF應該為constexpr const類型*/
    constexpr int &conexprPtrD = g_tempA;
    constexpr int &conexprPtrE = g_conTempA;
    constexpr int &conexprPtrF = g_conexprTempA;
    /*4.正常運行,編譯通過*/
    constexpr const int &conexprConPtrD = g_tempA;
    constexpr const int &conexprConPtrE = g_conTempA;
    constexpr const int &conexprConPtrF = g_conexprTempA;

    return 0;
}

  總結:簡單的說constexpr所引用的對象必須在編譯期就決定地址。還有一個奇葩的地方就是可以通過上例conexprPtrD來修改g_tempA的值,也就是說constexpr修飾的引用不是常量,如果要確保其實常量引用需要constexpr const來修飾。

5.修飾類(未完待續)


免責聲明!

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



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