Constexpr变量评估

时间:2015-07-12 23:47:52

标签: c++ constexpr compile-time compile-time-constant

这是我的代码,我需要澄清发生的事情:

constexpr int funct(int x){
    return x + 1;
}


int main(){
    int x = funct(10);
    return 0;
}

constexpr允许编译时计算,并且根据我上面的代码,由于funct被声明为constexpr,因此允许进行编译时计算参数是常数或constexpr本身。

我感到困惑的部分在于int x。由于它未声明为constexpr,是否意味着int x将在运行时获取值?这是否意味着声明它为constexpr int x意味着int x将在编译时获得与int x不同的值?

1 个答案:

答案 0 :(得分:4)

这取决于许多计数中的编译器。可能发生什么样的优化等等。但是,constexpr本身并不能实现编译时计算。

拿这段代码:

#include <cstdio>

constexpr int test(int in)
{
   return in + 25;
}

int main(int argc, char* argv[])
{
   printf("Test: %u\n", test(5));
   printf("Two: %u\n", test(10));
}

在我的x86_64 Gentoo框中的GCC 4.8.4下,实际上仍然会对所谓的编译时“测试”进行调用。我使用的线是

g++ -std=c++11 -Wall -g  -c main.cpp -o obj/Debug/main.o
g++  -o bin/Debug/TestProject obj/Debug/main.o   

所以在上面的代码中,产生了以下机器代码:

0x40061c    mov    edi,0x5
0x400621    call   0x400659 <test(int)>
0x400626    mov    esi,eax
0x400628    mov    edi,0x4006f4
0x40062d    mov    eax,0x0
0x400632    call   0x4004f0 <printf@plt>
0x400637    mov    edi,0xa
0x40063c    call   0x400659 <test(int)>
0x400641    mov    esi,eax
0x400643    mov    edi,0x4006fd
0x400648    mov    eax,0x0
0x40064d    call   0x4004f0 <printf@plt>

“测试”的asm块是:

0x400659    push   rbp 
0x40065a    mov    rbp,rsp
0x40065d    mov    DWORD PTR [rbp-0x4],edi
0x400660    mov    eax,DWORD PTR [rbp-0x4]
0x400663    add    eax,0x19
0x400666    pop    rbp
0x400667    ret

因此,正如您在那种情况下所看到的那样,它似乎对GCC如何生成该代码几乎没有影响。即使你这样做,你仍然会得到运行时计算:

int value = test(30);
printf("Value: %u\n", value);

产生这种情况的地方(由于添加了更多代码,测试地址略有改变):

0x40061c    mov    edi,0x1e
0x400621    call   0x40067a <test(int)>
0x400626    mov    DWORD PTR [rbp-0x4],eax
0x400629    mov    eax,DWORD PTR [rbp-0x4]
0x40062c    mov    esi,eax
0x40062e    mov    edi,0x400714
0x400633    mov    eax,0x0
0x400638    call   0x4004f0 <printf@plt>

如果您将值本身声明为constexpr,它确实会产生预期的结果:

constexpr int value = test(30);
printf("Value: %u\n", value);

相关代码是:

0x400623    mov    esi,0x37
0x400628    mov    edi,0x400714
0x40062d    mov    eax,0x0
0x400632    call   0x4004f0 <printf@plt>

基本上,如果你只是在constexpr中添加方法声明,那么就不能保证编译时计算。您还需要将变量声明为constexpr并分配给它。执行此类声明实际上要求编译器静态评估结果。如果您尝试这样做并且“test”未被声明为constexpr,GCC实际上会对您大喊:

  

main.cpp | 10 | error:调用非constexpr函数'int test(int)'|