C++ constexpr 实现差异
C++ constexpr realization differencies
刚刚了解了 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;
}
对这种行为有什么合理的解释吗?
Link 到 godbolt 示例:https://godbolt.org/z/ez7luu
所有编译器都是正确的。
一个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);
我们在compiler-can-choose区域,因为2
是编译时已知的,所以编译器可以选择编译时计算,但是要求的值不是[=16] =] 变量,因此不需要编译时值。
您会看到两个编译器正在计算编译时间,另外两个编译器在计算 运行 时间。通常,这种行为在很大程度上取决于优化级别。事实上,所有编译器都会为您示例中的编译标志生成不同的输出 after adding -O2
。
在你的第二个版本中
constexpr int c = square(2);
square()
值是为 constexpr
变量请求的,因此所有编译器 必须 计算 square(2)
编译时间(并且它们可以这样做,因为 2
是一个编译时已知的值)。
刚刚了解了 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;
}
对这种行为有什么合理的解释吗?
Link 到 godbolt 示例:https://godbolt.org/z/ez7luu
所有编译器都是正确的。
一个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);
我们在compiler-can-choose区域,因为2
是编译时已知的,所以编译器可以选择编译时计算,但是要求的值不是[=16] =] 变量,因此不需要编译时值。
您会看到两个编译器正在计算编译时间,另外两个编译器在计算 运行 时间。通常,这种行为在很大程度上取决于优化级别。事实上,所有编译器都会为您示例中的编译标志生成不同的输出 after adding -O2
。
在你的第二个版本中
constexpr int c = square(2);
square()
值是为 constexpr
变量请求的,因此所有编译器 必须 计算 square(2)
编译时间(并且它们可以这样做,因为 2
是一个编译时已知的值)。