C++20重量级特性:Constexpr增强

文摘   2024-12-16 12:07   新加坡  

点击上方蓝字 江湖评谈设为关注/星标




前言

C++20常量表达式(Constexpr),顾名思义:函数或者变量在编译期间,而不是运行期间就可以计算出来的结果视为常量,这种过程叫做常量表达式的计算。常量表达式在这期间起到了至关重要的作用,C++20对Constexpr进行了显著的增强,进一步扩宽了编译时求值的能力,使得编译期计算更加灵活和强大。本篇看下。

Constexpr

函数在编译期间就可以计算出其结果,constexpr 修饰,表示它可以在编译时计算。其形态如下:

constexpr 返回类型 函数名(参数列表) {    // 函数体}

例子:

constexpr int square(int x) {    return x * x;}
int main() {    constexpr int result = square(5);  // 在编译时计算    // 此时 result 的值是 25,编译器在编译时就完成了计算}

C++11只支持了简单的计算以及部分特性,C++20如下介绍:

1.支持容器的颗粒化操作

这些颗粒化包括,编译期间的优化,编译期间的数据长度固定,编译期间的计算以及编译期间的各种操作,例子如下:

#include <iostream>#include <array>
constexpr int square(int x) {    return x * x;}
constexpr int sum_of_squares(const std::array<int5>& arr) {    int sum = 0;    for (size_t i = 0; i < arr.size(); ++i) {        sum += square(arr[i]);    }    return sum;}
int main() {    constexpr std::array<int5> arr = {12345};
    constexpr int result = sum_of_squares(arr);  // 在编译时计算
    std::cout << "Sum of squares: " << result << std::endl;}

求数组元素的平方和结果,通过容器std::aary来存储。编译期间sum_of_squares/square函数就已经被计算出来了,且sum_of_squares传入的参数固定长度为5,sum_of_squares/square的操作分别是计算单个元素的平方和计算平方的和,且返回。

这里里面的优化是,因为sum_of_squares/square函数被标记为constexpr,所以编译期间直接计算出了结果。运行期间不需要任何运算,只需要把这个结果带入到后续的操作即可。

2.静态断言和constexpr结合操作,限制编译条件

例子,

//filename:hello.cconstexpr int max_value = 100;
static_assert(max_value <= 100"max_value must be less than or equal to 100");
int main() {    // 如果 max_value 大于 100,这里会引发编译错误    return 0;}

如果max_value=101的话,会报以下错误。只要小于100都会正常运行:

# g++ -std=c++20 -o hello hello.c hello.c:3:25: error: static assertion failed: max_value must be less than or equal to 100    3 | static_assert(max_value <= 100, "max_value must be less than or equal to 100");      |               ~~~~~~~~~~^~~~~~hello.c:3:25: note: the comparison reduces to ‘(101 <= 100)’

3.constexpr支持内存分配和释放

也就是是说,在编译期间,可以动态的分配和释放内存,这也是constexpr的神奇地方。

#include <iostream>
struct MyStruct {    int x, y;    MyStruct(int a, int b) : x(a), y(b) {}};
constexpr MyStruct* create_struct(int a, int b) {    return new MyStruct(a, b);}
int main() {    constexpr MyStruct* ptr = create_struct(1020);    std::cout << ptr->x << ", " << ptr->y << std::endl;    // 不可以在 runtime 执行 constexpr 函数的动态分配    // 所以这段代码会在编译时报错。}

4.constexpr支持其它更多操作,比如递归

#include <iostream>#include <stdexcept>
constexpr int factorial(int n) {    if (n < 0) {        throw std::invalid_argument("Negative value is not allowed");    }    return n == 0 ? 1 : n * factorial(n - 1);}
int main() {    constexpr int result = factorial(5);  // 编译时计算阶乘    static_assert(result == 120, "Compile-time factorial failed!");    std::cout << "Sum of squares: " << result << std::endl;}

5.支持动态内存分配

比如,std:array,std::string,std::vector在编译期间使用动态内存和动态容器。

#include <vector>#include <iostream>
constexpr int sum(const std::vector<int>& v) {    int total = 0;    for (int n : v)        total += n;    return total;}
int main() {    constexpr std::vector<int> v = {123};    constexpr int result = sum(v);  // 在编译时计算结果    static_assert(result == 6, "Compile-time sum failed!");}

结尾

以上介绍了constexpr增强的地方,比如颗粒化操作,限制编译条件,内存分配释放,递归以及动态内存等等。这些东西,都可以在编译期间确定,显著的增强C++的性能。

往期精彩回顾

C++20重量级特性

C++20重量级特性:协程

C++20重量级特性:Modules


关注公众号↑↑↑:江湖评谈 


江湖评谈
记录,分享,自由。
 最新文章