使用 if constexpr 实现条件编译
在项目开发中,我们通常会使用条件编译对代码进行裁剪,选择性地排除不需要的代码,比如在某个平台下完全不支持某个功能,那么这个功能就不应该被编译。
一般我们使用宏来判断代码,选择性的挑选需要编译的部分,并在构建系统中开启这样的条件。
|
在 C 语言的项目中,这样的行为是很正常的,甚至在 C++ 项目中,我们也会选择使用宏进行条件判断。
但是如果定义的宏多了,则很容易导致代码碎片化,并且无法直观地看到工作流程。
例如这样的代码:
|
从上面的例子中可以看到,代码中一旦出现大量重复的判断条件,代码非常不直观,而且被宏分割成了很多部分。
在一次偶然的机会,我看到了一篇介绍 C++ 17 中的 if constexpr 的用法,可以在编译期进行一些计算,虽然我很早就知道了 constexpr 的用法,但是大家举的例子基本上都是数值计算,让编译器在编译期间将数值进行计算,从而减轻运行时的消耗,我也从来想到其他用法,所以一直没有在项目中使用到。
constexpr 的作用并不是编译期计算数值,而是编译期进行的代码分析,如果代码较小且非常直观,比如大家经常举的例子,在编译期间计算斐波那契数列,这种例子即使不使用 constexpr 显式要求,编译器也会帮助我们开启优化,直接给出结果。
但是如果代码非常复杂,编译器就不一定会为我们做这样的优化,就需要我们手动标记可以计算的位置,要求编译器在编译期间进行求值和优化。
我设想的是,使用 cmake 在构建时,先生成一份文件,将开关的值记录下来,在需要进行判断的地方,就可以直接使用 if constexpr 进行条件判断,在编译期间,编译器会发现有一个分支确定不会被执行(相当于 if(false) {}
),那么这个分支就不会进行编译,直接剔除。
CMakeLists.txt 中需要做一些工作,将编译参数加入构建系统。
option (ENABLE_MODULE "Enable Module" ON) |
在 options/options.h.in 文件里,按照 cmake 的要求将变量导入进文件中,进行内容替换。
|
这里我仍然使用的是宏定义,也可以直接写成如下形式:
option (ENABLE_MODULE "Enable Module" ON) |
|
在 main.cpp 中写一段测试代码:
|
执行结果是符合预期的。
# lxz @ lxz-MacBook-Pro in ~/Develop/constexpr-demo/build on git:master o [13:28:39] |
虽然结果是符合的,但是我们其实不确定是否真的在编译期间就完成了代码剔除,所以使用命令进行汇编,查看汇编中是否包含了判断指令和两段输出的字符串。
clang -S main.cpp -o main.s -I./ |
main.s
.text |
查看整个 main.s 汇编,发现只在 .L.str 段中有预期的文本字符串,可以得出结论,代码是在编译期间完成了剔除,符合我们的要求。