关键字constexpr(C++)

关键字constexpr在C++11中引入的,并且在C++14中得到了改进。像const一样,它可以应用于变量:当任何代码试图去修改该值时,都会引发编译器错误;与const不同,constexpr也可以应用于函数和类构造函数。constexpr表示该值或返回值是恒定的,并在可能的情况下在编译时进行计算。

constexpr整数值可在需要const整数的任何地方使用,例如,在模板参数和数组声明中。当在编译时而不是运行时计算一个值时,它可以帮助您的程序更快地运行并使用更少的内存。   

为了限制编译时常量计算的复杂性及其对编译时间的潜在影响,C++14标准要求在常量表达式中的类型必须是 literal types 。

句法(Syntax)

constexpr literal-type identifier = constant-expression ;
constexpr literal-type identifier { constant-expression } ;
constexpr literal-type identifier ( params ) ;
constexpr ctor ( params ) ;

参数(Parameters)

params

一个或多个参数,每个参数必须是 literal types,并且本身必须是常量表达式。

返回值(Return value)

一个constexpr变量或者函数必须返回一个 literal types.

constexpr变量(constexpr variables)

constconstexpr变量之间的主要区别是const变量的初始化可以推迟到运行时。 constexpr变量必须在编译时初始化。所有constexpr变量都是const

  • 变量是  literal types 并已初始化时,可以使用constexpr声明。如果初始化由构造函数执行,则必须将构造函数声明为constexpr

  • 当满足这两个条件时,可以将引用声明为constexpr:被引用的对象由常量表达式初始化,并且初始化期间调用的任何隐式转换也是常量表达式。

  • constexpr变量或函数的所有声明必须具有constexpr说明符。

constexpr float x = 42.0;
constexpr float y{108};
constexpr float z = exp(5, 3);
constexpr int i; // Error! Not initialized
int j = 0;
constexpr int k = j + 1; //Error! j not a constant expression

constexpr 函数(constexpr functions)

constexpr函数是一种在使用代码需要时可以在编译时计算其返回值的函数。使用代码需要在编译时返回值以初始化constexpr变量或提供非类型(non-type)模板参数。当其参数为constexpr值时,constexpr函数将生成一个编译时常量。当使用非constexpr参数(non-constexpr arguments)调用时,或者在编译时不需要其值时,它将在运行时像常规函数一样生成一个值。 (这种双重行为使您不必编写同一函数的constexpr和非constexpr版本。)

constexpr函数或构造函数是隐式内联的。

以下规则适用于constexpr函数:

  • constexpr函数必须仅接受并返回 literal types

  • constexpr函数可以是递归的。

  • 它不能是虚拟的。当封闭类具有任何虚拟基类时,不能将构造函数定义为constexpr

  • 正文可以定义为= default或= delete。

  • 该主体不能包含goto语句或try块。

  • 非 constexpr模板(non-constexpr template)的显式特化(explicit specialization)可以声明为 constexpr

  • constexpr模板的显式专业化(explicit specialization)也不必是constexpr

以下规则适用于Visual Studio 2017和更高版本中的constexpr函数:

  • 它可能包含ifswitch语句,以及所有循环语句,包括for,基于范围的forwhiledo-while

  • 它可能包含局部变量声明,但是必须初始化该变量。它必须是 literal types ,并且不能是static的或thread-local的。本地声明的变量不需要为const,并且可以变异。

  • constexpr非静态成员函数不需要为隐式const

constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

提示

在Visual Studio调试器中,调试未优化的Debug版本时,可以通过在其中放置一个断点来判断是否在编译时评估constexpr函数。如果命中了断点,则会在运行时调用该函数。如果不是,则在编译时调用该函数。

extern constexpr

The /Zc:externConstexpr compiler option causes the compiler to apply external linkage to variables declared by using extern constexpr. In earlier versions of Visual Studio, either by default or when /Zc:externConstexpr- is specified, Visual Studio applies internal linkage to constexpr variables even when the extern keyword is used. The /Zc:externConstexpr option is available starting in Visual Studio 2017 Update 15.6, and is off by default. The /permissive-option doesn't enable /Zc:externConstexpr.

Example

以下示例显示constexpr变量,函数和用户定义的类型。在main()的最后一条语句中,constexpr成员函数GetValue()是运行时调用,因为不需要在编译时知道该值。

// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>

using namespace std;

// Pass by value
constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp2(x * x, n / 2) :
        exp2(x * x, (n - 1) / 2) * x;
}

// Compile-time computation of array length
template<typename T, int N>
constexpr int length(const T(&)[N])
{
    return N;
}

// Recursive constexpr function
constexpr int fac(int n)
{
    return n == 1 ? 1 : n * fac(n - 1);
}

// User-defined type
class Foo
{
public:
    constexpr explicit Foo(int i) : _i(i) {}
    constexpr int GetValue() const
    {
        return _i;
    }
private:
    int _i;
};

int main()
{
    // foo is const:
    constexpr Foo foo(5);
    // foo = Foo(6); //Error!

    // Compile time:
    constexpr float x = exp(5, 3);
    constexpr float y { exp(2, 5) };
    constexpr int val = foo.GetValue();
    constexpr int f5 = fac(5);
    const int nums[] { 1, 2, 3, 4 };
    const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };

    // Run time:
    cout << "The value of foo is " << foo.GetValue() << endl;
}

要求(Requirements)

Visual Studio 2015或更高版本。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值