天天看點

c++11總結20——constexpr1. 概念2. 使用與限制3. c++14優化4. 示例

1. 概念

c++11引入的關鍵字,用于編譯時擷取常量或常量函數的結果。

constexpr修飾普通變量時,變量必須經過初始化且初始值必須是一個常量表達式。

2. 使用與限制

c++11之前的常量表達式不允許包含函數調用或對象構造,如下所示:

int rValue() {
    return 1;
}

int m_iValue[rValue() + 2];  //c++03中error
           

c++11引入關鍵字constexpr,允許程式設計者保證函數或對象的構造函數是編譯時常量,代碼改寫如下:

constexpr int rValue() {
    return 1;
}

int m_iValue[rValue() + 2];  //c++11 ok
           

限制總結如下:

  • 函數的傳回值不能時void類型;
  • 函數體不能聲明變量或定義新類型;
  • 函數體隻能包含聲明、null語句或者一條return語句;
  • 在形參實參結合後,return語句中的表達式為常量表達式;

為構造使用者定義類型的常量表達式,構造函數必須用constexpr聲明,函數體僅包含聲明或null語句,不能聲明變量或定義類型。是以,構造函數的實參值應該是常量表達式,直接初始化類的資料成員。析構函數是平凡的。類型的拷貝構造函數應該也定義為constexpr,以允許constexpr函數傳回一個該類型的對象。類型的成員函數都應該是constexpr。

constexpr函數或構造函數的實參值如果不是常量表達式,那麼調用行為與結果就不是常量表達式。

3. c++14優化

c++14放松了限制。聲明為constexpr的函數可以含有以下内容:

  • 任何聲明,除了:
    • static

      thread_local

      變量。
    • 沒有初始化的變量聲明。
  • 條件分支語句

    if

    switch

  • 所有的循環語句,包括基于範圍的

    for

    循環。
  • 表達式可以改變一個對象的值,隻需該對象的生命期在聲明為constexpr的函數内部開始。包括對有

    constexpr

    聲明的任何非

    const

    非靜态成員函數的調用。

goto仍然不允許在constexpr函數中出現。

constexpr支援編譯期的遞歸。例如,可以寫一個constexpr函數計算斐波那契數列。

此外,C++11指出,所有被聲明為constexpr的非靜态成員函數也隐含聲明為const(即函數不能修改*this的值)。C++14已經删除此點,非靜态成員函數可以為非const

4. 示例

// C++98/03
template <int N>
struct Factorial_Cpp03
{
    const static int value = N * Factorial_Cpp03<N - 1>::value;
};
template <>
struct Factorial_Cpp03<0>
{
    const static int value = 1;
};

// C++11
constexpr int factorial_Cpp11(int n)
{
    return n == 0 ? 1 : n * factorial_Cpp11(n - 1);
}

// C++14
constexpr int factorial_Cpp14(int n)
{
    int result = 1;
    for (int i = 1; i <= n; ++i)
        result *= i;
    return result;
}

int main()
{
    static_assert(Factorial_Cpp03<3>::value == 6, "error");
    static_assert(factorial_Cpp11(3) == 6, "error");
    static_assert(factorial_Cpp14(3) == 6, "error");
    return 0;
}
           

部分參考:https://zh.wikipedia.org/wiki/Constexpr

繼續閱讀