C++ g++;编译器将constexpr函数视为常规函数,以防其返回值未被使用?

C++ g++;编译器将constexpr函数视为常规函数,以防其返回值未被使用?,c++,g++,constexpr,C++,G++,Constexpr,我曾尝试查看由g++编译的cpp constexpr函数的编译代码。 我看到,如果函数不返回任何内容,编译器会将其视为常规函数,但如果它返回一个值,并且我将该值赋给一个constexpr变量,则只会在编译时对其进行计算 代码示例: constexpr int func(int x){ return x!=0 ? 1: throw "Error"; } int main(){ func(2); } 和编译器输出: push rbp mov rbp, rsp mov

我曾尝试查看由g++编译的cpp constexpr函数的编译代码。 我看到,如果函数不返回任何内容,编译器会将其视为常规函数,但如果它返回一个值,并且我将该值赋给一个constexpr变量,则只会在编译时对其进行计算

代码示例:

constexpr int func(int x){
   return x!=0 ? 1: throw "Error";
}

int main(){
    func(2);
}
和编译器输出:

push    rbp
mov     rbp, rsp
mov     edi, 2
call    func(int)
mov     eax, 0
pop     rbp
ret
main:
    push    rbp
    mov     rbp, rsp
    mov     DWORD PTR [rbp-4], 1
    mov     eax, 0
    pop     rbp
    ret
正如您所看到的,它在运行时调用func。相反,如果我将函数结果赋值为constexpr:

constexpr int func(int x){
    return x!=0 ? 1: throw "Error";
}

int main(){
   constexpr int x = func(2);
}
和编译器输出:

push    rbp
mov     rbp, rsp
mov     edi, 2
call    func(int)
mov     eax, 0
pop     rbp
ret
main:
    push    rbp
    mov     rbp, rsp
    mov     DWORD PTR [rbp-4], 1
    mov     eax, 0
    pop     rbp
    ret

有人能解释一下为什么编译器在编译时而不是在运行时对函数求值时需要这个赋值吗?

编译器可以决定是在编译时还是在运行时对constepr函数求值。只有在需要编译时常量表达式的上下文中使用函数时(例如使用结果初始化
constexpr
变量),编译器必须在编译时计算函数

在第一个示例中,情况并非如此,因为您可能是在调试模式下编译的,所以在运行时调用该函数,就像其他所有函数一样

引用(由我强调):

constexpr说明符声明可以在编译时计算函数或变量的值。这样的变量和函数可以在只允许编译时常量表达式的情况下使用(前提是给出了适当的函数参数)


如果您使用例如
-O3
编译第一个示例,您将看到函数调用已优化。

直到您可以使用
int
void
表达式作为conditional@M.M仅当
void
表达式是
throw
表达式时,因此不需要在条件表达式的结果类型中考虑它,因为
抛出
,如果执行,无法为它生成一个值。奇怪的是,如果我将它编译为O3,那么编译器似乎只是将我的函数内联起来,而不是在编译时真正对它进行赋值。例如,如果我将值0传递给函数(我希望这样的constexpr函数会导致编译时错误)它将抛出内联到main,并在运行时抛出异常如果constexpr函数中的代码路径抛出,则该函数不能用于需要编译时常量表达式的上下文中。请看这里: