C++14尝鲜:constexpr函数(编译期函数)

constexpr

constexpr是constant expression(常量表达式)的缩写,它是C++11新引进的关键字。使用constexpr关键字可以声明编译期的变量和函数。

constexpr函数

要声明constexpr函数(编译期的函数),必须在函数声明前添加constexpr关键字。

#include 
using namespace std;
// C++98/03
template struct Factorial
{
    const static int value = N * Factorial::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之后进行数值计算时,无论在编译期还是运行期我们都可以统一用一套代码来实现。编译期和运行期在数值计算这点上得到了部分统一。

你可能感兴趣的:(C++)