【学习笔记】C++ 编译时计算

做编译时计算的 motivation 是非常显著的,如果有一个对象在编译阶段就可以完全确定,那么我们在编译阶段 prefill 它,运行时的开销将会减少。

在 modern cpp 中为编译时计算提供了一些接口,这里以 constexprconsteval 为例

  • 使用 constexpr 来定义变量

    字面类型(在编译时可以确定的 class,最简单的例如 int char bool)的 constexpr 就不多说了,赋一个 constexpr 的值就合法,否则不合法

    对于一个自己定义的 class/struct,要想让这个类型的实例是编译时可计算的,需要满足构造函数是 constexpr,同时需要满足这个 class 没有虚函数,没有虚基类(我有点没想通,如果虚基类的所有函数都派生过了,也就行了?)。

  • constexpr 不仅可以用来定义变量,还可以定义一个函数。

    在定义函数时,函数的参数不需要保证是 constexpr(如果是 constexpr 甚至无法通过编译),可以正常写 typename。
    但是如果代码某个地方调用了返回值为 constexpr 的函数,那么调用时传入的参数必须都是 constexpr。此时函数会在编译时根据参数运行并得到结果。
    这里有些值得思考的问题,例如对于递归调用的 constexpr 函数,它在传参时有什么要注意的地方吗?还是没有任何要注意的地方,毕竟函数内定义、完成计算的变量只需要满足外部调用传递的时 constexpr,就能保证它也是 constexpr 了?

    有一个有趣的事情,constexpr 函数的返回值赋给一个变量,如果这个变量的类型也是 constexpr,那么这个变量的值会在编译时算出来,否则不会。这也是符合逻辑的。[1]

    另外有一个说法是,c++11 不支持 constexpr 函数超过一行(于是可以用三目运算符来实现分支结构??),而 c++14 和之后的版本解决了这个问题。

  • C++20 的 consteval 扩展

    针对 [1] 中提到的这个现象,cpp 引入了 consteval 关键字,要求一个函数必须在编译时完成与它相关的所有计算(调用求值),如果尝试在运行时调用这个函数将报错。


bonus:通过编译时计算的方法,预处理一个 \(m\le n \le 5000\) 的二维数组 C[n][m]?这是一个随机问题,我也没想可以怎么实现。

posted @ 2025-04-17 10:19  yspm  阅读(90)  评论(1)    收藏  举报