1. 程式人生 > >C++14嚐鮮:constexpr函式(編譯期函式)

C++14嚐鮮:constexpr函式(編譯期函式)

constexpr

constexpr是constant expression(常量表達式)的縮寫,它是C++11新引進的關鍵字。使用constexpr關鍵字可以宣告編譯期的變數和函式。

constexpr函式

要宣告constexpr函式(編譯期的函式),必須在函式宣告前新增constexpr關鍵字。

#include <iostream>
using namespace std;
// C++98/03
template<int N> struct Factorial
{
    const static int value = N * Factorial<N - 1>::value;
};
template<> struct Factorial<0>
{
    const static int value = 1;
};
// C++11
constexpr int factorial(int n)
{
    return n == 0 ? 1 : n * factorial(n - 1);
}
// C++14
constexpr int factorial2(int n)
{
    int result = 1;
    for (int i = 1; i <= n; ++i)
        result *= i;
    return result;
}

int main()
{
    static_assert(Factorial<3>::value == 6, "error");
    static_assert(factorial(3) == 6, "error");
    static_assert(factorial2(3) == 6, "error");
    int n = 3;
    cout << factorial(n) << factorial2(n) << endl; //66
}

程式碼說明:

  • 以上程式碼演示瞭如何在編譯期計算3的階乘。
  • 在C++11之前,在編譯期進行數值計算必須使用模板超程式設計技巧。具體來說我們通常需要定義一個內含編譯期常量value的類模板(也稱作元函式)。這個類模板的定義至少需要分成兩部分,分別用於處理一般情況和特殊情況。
    程式碼示例中Factorial元函式的定義分為兩部分:
    當模板引數大於0時,利用公式 N!=N*(N-1)! 遞迴呼叫自身來計算value的值。
    當模板引數為0時,將value設為1這個特殊情況下的值。
  • 在C++11之後,編譯期的數值計算可以通過使用constexpr宣告並定義編譯期函式來進行。相對於模板超程式設計,使用constexpr函式更貼近普通的C++程式,計算過程顯得更為直接,意圖也更明顯。
    但在C++11中constexpr函式所受到的限制較多,比如函式體通常只有一句return語句,函式體內既不能宣告變數,也不能使用for語句之類的常規控制流語句。
    如factorial函式所示,使用C++11在編譯期計算階乘仍然需要利用遞迴技巧。
  • C++14解除了對constexpr函式的大部分限制。在C++14的constexpr函式體內我們既可以宣告變數,也可以使用goto和try之外大部分的控制流語句。
    如factorial2函式所示,使用C++14在編譯期計算階乘只需利用for語句進行常規計算即可。
  • 雖說constexpr函式所定義的是編譯期的函式,但實際上在執行期constexpr函式也能被呼叫。事實上,如果使用編譯期常量引數呼叫constexpr函式,我們就能夠在編譯期得到運算結果;而如果使用執行期變數引數呼叫constexpr函式,那麼在執行期我們同樣也能得到運算結果。
    程式碼第32行所演示的是在執行期使用變數n呼叫constexpr函式的結果。
    準確的說,constexpr函式是一種在編譯期和執行期都能被呼叫並執行的函式。出於constexpr函式的這個特點,在C++11之後進行數值計算時,無論在編譯期還是執行期我們都可以統一用一套程式碼來實現。編譯期和執行期在數值計算這點上得到了部分統一。