只是了解了 constexpr 函数,然后去了 godbolt 来了解编译器如何优化代码,并发现编译器的行为完全不同。
具有以下代码:
constexpr int square(int num) {
return num * num;
}
int main() {
int a = square(2);
}
g ++ 和 icc 编译器计算函数结果并将其分配给变量(如我所料),但是 msvc 和 clang 调用功能。
要使用优化,我们应该执行其他步骤:
constexpr int square(int num) {
return num * num;
}
int main() {
constexpr int c = square(2);
int a = c;
}
对这种行为有合理的解释吗?
链接到godbolt示例:https://godbolt.org/z/ez7luu
答案 0 :(得分:3)
所有编译器都是正确的。
constexpr
函数是可以根据情况在编译时或运行时计算的函数。
假装没有as-if rule,我们可以说当constexpr
函数的结果到达要求进行编译的地方时,编译器必须计算编译时间。被称为编译时间。
例如,一个数组的大小
int a[square(10)];
或模板参数
std::array<int, square(10)> a;
或constexpr
变量
constexpr int a { square(10) };
在某些情况下,必须在运行时计算功能 ,例如在接收运行时已知的输入值时;例如
int a;
std::cin >> a;
int b { square(a) };
否则,编译器可以选择是计算编译时间还是运行时间。
在您的第一个版本中
int a = square(2);
我们在编译器可以选择的区域,因为2
是已知的编译时,因此编译器可以选择编译时计算,但是该值是为非constexpr
请求的变量,因此不需要编译时值。
您会看到两个编译器正在计算编译时,另外两个正在运行。通常,这种行为在很大程度上取决于优化级别。实际上,所有编译器都会对示例中的编译标志产生不同的输出after adding -O2
。
第二版
constexpr int c = square(2);
为square()
变量请求constexpr
值,因此所有编译器必须计算square(2)
编译时(他们可以这样做,因为{ {1}}是一个已知的编译时值。