C++ constexpr 实现差异

C++ constexpr realization differencies

刚刚了解了 constexpr 函数并访问了 godbolt 以了解编译器如何优化代码并发现编译器的行为完全不同。

有以下代码:

constexpr int square(int num) {
    return num * num;
}

int main() {
    int a = square(2);
}

g++icc 编译器计算函数结果并将其分配给变量(如我所料),但是 msvcclang 调用函数。

要使用优化,我们应该进行额外的步骤:

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 是一个编译时已知的值)。