C++:constexpr

本文详细介绍了C++11及C++14中的constexpr关键字,包括其语法、参数、返回值规则,以及在变量和函数中的应用。constexpr用于创建常量表达式,使得值能在编译时计算,提高程序效率。文中还探讨了constexpr变量的初始化、constexpr函数的特性,以及使用示例。

简介

关键字 constexpr 是在 c + + 11 中引入的,并在 c + + 14 中得到改进。 它表示* const ant 表达式*。 与类似 const ,可将其应用于变量:当任何代码尝试将值进行 mod 时,将引发编译器错误 if 。 与不同 const , constexpr 还可以应用于函数和类 const ructors。 constexpr 指示值或返回值为 ant,并在 const 编译时计算(如果可能)。

constexpr 整数值可用于需要整数的任何位置 const ,例如模板参数和数组声明中的。 在编译时(而非运行时)计算某个值时,它可帮助您的程序运行速度更快,使用更少的内存。

为了限制编译时 ant 计算的复杂性 const ,以及它们对编译时间的潜在影响,c + + 14 标准要求 ant 表达式中的类型为 const 文本类型。

语法

constexpr文本类型 ident if ier = * const * ;
**constexpr*文本类型 ident if ier { * const ant-expression } ;
**constexpr文本类型 ident if ier ** ( 参数 **) ** ;
**constexprctor ** ( 参数 **) ** ;

参数


一个或多个参数,每个参数必须是文本类型,并且本身必须是 const ant 表达式。

返回值

constexpr 变量或函数必须返回文本类型。

constexpr 变量

和变量的主要 d if f) const constexpr 是在 const 运行时,可以将变量的初始化推迟。 constexpr 变量必须在编译时进行初始化。 所有 constexpr 变量都是 const 。

constexpr 如果变量具有文本类型并已初始化,则可以使用声明该变量。 如果初始化 for 由 ructor 按 med-v 进行 const ,则 const 必须将 ructor 声明为 constexpr 。

constexpr 当同时满足这两个条件时,可以声明引用:引用的对象由 const ant 表达式进行初始化,并且在初始化期间调用的任何隐式转换也是 const ant 表达式。

变量或函数的所有声明都 constexpr 必须具有 constexpr 规范 if ier。

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 当使用代码需要函数时,该函数的返回值可在编译时。 使用代码要求在编译时返回值以初始化 constexpr 变量,或提供一个非类型模板参数。 如果其参数为 constexpr 值, constexpr 函数将生成编译时 const ant。 使用非参数调用时 constexpr ,或在编译时不需要其值时,它会在运行时生成一个值,如常规函数。 (这种双重行为使您不必编写 constexpr 同一函数的和非 constexpr 版本。 )

constexpr 函数或 const ructor 是隐式的 inline 。

以下规则适用于 constexpr 函数:

constexpr 函数必须接受并仅返回文本类型。

constexpr 函数可以是递归的。

它不能是 虚拟的。 const不能定义 ructor,因为 constexpr 封闭类具有任何虚拟基类。

主体可以定义为 = default 或 = delete。

主体不能包含任何 goto 语句或 try 块。

非模板的显式专用化 constexpr 可以声明为 constexpr :

模板的显式专用化 constexpr 还不一定要 constexpr :

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

它可以包含 if 和 switch 语句以及所有循环语句,包括 for 、基于范围的 for 、 while 和。 ** while **

它可能包含局部变量声明,但必须对变量进行初始化。 它必须是文本类型,不能是 static 或线程本地类型。 本地声明的变量不需要为 const ,并且可能会改变。

constexpr 非 static 成员函数不需要是隐式的 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 调试器中,调试未优化的调试版本时,可以 constexpr 通过在函数内放置一个断点来确定是否在编译时计算该函数。 如果命中该断点,则在运行时调用该函数。 如果未命中,则在编译时调用该函数。

示例

下面的示例演示 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;
}

该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处
本文章博客地址:https://blog.youkuaiyun.com/it_cplusplus/article/details/118228311

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值