C++ constexpr是否会改变编译器输出,促使其完成原本不会的编译期计算?
现象观察
通过Compiler Explorer测试发现,GCC可以将逻辑稍复杂的函数在编译期转换为常量值。例如以下代码:
int func2(int x, int y) { return x ^ y; } int func(int x, int y) { int i,j; int k=0; for (i=0; i<x; i++) for (j=0; j<y; j++) { k += i*j + func2(i,j); } return k; } int main() { int x; x = func(4, 7); return x; }
GCC会直接将main函数的返回值替换为216,且此处未使用constexpr关键字,是编译器自行完成了编译期计算。
资料中的矛盾点
- 部分关于
constexpr的资料声称:该关键字的作用是告知编译器此处可进行编译期优化,使其在编译期完成计算,若无该关键字则不会执行。 - StackOverflow的一则回答指出:
constexpr的主要用途是声明意图。
问题解答
constexpr确实会改变编译器的输出,让它完成原本不会做的编译期计算,但这只是它的作用之一,更本质的是它在C++标准层面定义了"常量表达式"的语义,而非单纯的优化提示。
具体可以从两个维度理解:
无constexpr时:编译期计算是可选优化
示例中的编译期计算属于编译器的优化行为——通过常量传播、函数内联、循环展开等手段,在输入为常量、逻辑可推导时主动完成计算。但这种优化不是必须的:比如在-O0(无优化)等级下,GCC就不会把func(4,7)转换为常量;而且如果函数逻辑过于复杂或输入不是常量,编译器也会放弃这种优化。有constexpr时:编译期计算是标准强制要求
当你将函数声明为constexpr,只要输入是常量表达式,C++标准就要求编译器必须在编译期完成计算(前提是函数符合constexpr的规则,比如无副作用、逻辑可在编译期求值)。哪怕在-O0等级下,编译器也会执行这个计算——因为这是语言语义的一部分,而非可选优化。"声明意图"的价值
constexpr同时明确了代码的意图:告诉编译器和其他开发者,这个函数是为常量计算设计的,它的实现必须符合常量表达式的规则。这不仅约束了函数的编写,也让代码的用途更清晰。
总结来说:没有constexpr,编译期计算是编译器"可做可不做"的优化;有constexpr,编译期计算是"必须做"的语义要求,它能让编译器完成那些原本因优化策略限制不会执行的编译期计算,同时明确代码的设计意图。
内容的提问来源于stack exchange,提问作者Rocketmagnet

