constexpr常数表达式

205 篇文章 38 订阅 ¥9.90 ¥99.00
本文介绍了C++中的constexpr关键字,用于创建常量表达式。constexpr可以用于变量和函数,确保它们在编译时计算。对于变量,constexpr要求在编译时初始化,而对于函数,如果其参数和返回值满足条件,可以在编译时求值。此外,还探讨了constexpr与指针的结合使用,说明了其在指针声明中的作用。
摘要由CSDN通过智能技术生成

关键字 constexpr 于 C++11 中引入并于 C++14 中得到改善。它表示常数表达式。与 const 相同,它可应用于变量,因此如果任何代码试图修改该值,均将引发编译器错误。与 const 不同,constexpr 也可应用于函数和类构造函数。 constexpr 指示值或返回值是常数,并且如果可能,将在编译时计算值或返回值。

constexpr 变量

const 和 constexpr 变量之间的主要区别在于:

const 变量的初始化可以延迟到运行时,而 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
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

一般来说,如果你认定变量是一个常量表达式,那就把它声明成为constexpr类型。

constexpr 函数

constexpr 函数是在使用需要它的代码时,可以在编译时计算其返回值的函数。当其参数为 constexpr 值并且在编译时使用代码需要返回值时(例如,初始化一个 constexpr 变量或提供一个非类型模板参数),它会生成编译时常量。使用非constexpr 参数调用时,或编译时不需要其值时,它将与正则函数一样,在运行时生成一个值。

#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(&ary)[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()
    {
        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);
    // const float a = 2.0;
    // const int  b  = 2;
    // constexpr float xx = exp2(a, b); // Error!
    constexpr float xx = exp2(2.0, 2);
    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 };

    cout << "The value of foo is " << foo.GetValue() << endl;

}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

3 constexpr和指针

还记得const与指针的规则吗?如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针本身是常量;如果出现在星号两边,表示被指物和指针两者都是常量。

const不同,在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指对象无关

const int *p     = 0; // non-const pointer, const data
constexpr int *q = 0; // const pointer, non-const data
 
 
  • 1
  • 2
  • 1
  • 2

与其它常量指针类似,const指针既可以指向常量也可以指向一个非常量:

int j = 0;
constexpr int i = 2;
constexpr const int *p = &i; // const pointer, const data
constexpr int *p1 = &j; // const pointer, non-const data
`constexpr` 表示在编译时计算的结果的表达式,这意味着它的值可以在编译时确定,而不是在程序运行时。这种类型的表达式允许编译器优化代码,使其执行更快,因为编译器能提前计算出结果并进行相应优化。 在C++中,当您在代码中遇到 `constexpr` 关键字时,它会告诉编译器: 1. **静态常量**: 当用于变量声明时,意味着这个变量是一个静态常量,只能赋值一次并且在编译时确定其值。一旦设置,它的值就不能改变。 ```cpp constexpr int pi = 3; // 错误:编译时将报错,因为3不是一个合法的表达式,应该是一个整数字面量。 ``` 正确的例子应该是使用整型数字: ```cpp constexpr int pi = 3; // 可以被正确编译 ``` 或者更复杂的表达式,例如: ```cpp constexpr int complex_pi = 2 * sizeof(int); ``` 2. **常量表达式**: 当用于函数或表达式时,表明这个表达式总是可以在编译时计算得到结果。这种类型的表达式包括基本运算、数组访问、算术运算、比较运算、条件运算等,以及一些特定的对象成员访问,只要它们在编译时能够得到确定的值即可。 ```cpp constexpr int add(const int &a, const int &b) { return a + b; } constexpr int result = add(5, 7); // 正确,因为在编译时就可以计算结果。 ``` 如果尝试在一个无法在编译时确定结果的表达式前加上 `constexpr`,则会触发编译错误。例如: ```cpp int x = 10; int y = 5; if (x > y) { constexpr int sum = x + y; // 错误,因为x和y的值取决于运行时的情况。 } ``` 在许多情况下,使用 `constexpr` 可以提高程序的效率,特别是在涉及到大量的循环迭代、数组长度确定、初始化常量数组等方面。同时,这也增加了代码的可预测性和可靠性,因为开发者和用户都知道编译器在编译时就已经完成了相应的计算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值