利用constexpr将计算从运行时提前至编译时
【说明】 C++11开始引入了constexpr标识符,开发者可以通过该标识符告诉编译器,被标识的变量或函数在符合条件时会尽量在编译时求值。这样做可以提升程序运行时的效率,但会以增加编译时间为代价。constexpr对被标识的变量和函数有非常多的限制条件,并且对于不同的C++标准来说,限制条件又有所不同。对于列举这些不同标准下的限制规则,超出了本指南的范畴,请参考C++语言标准。
【注意事项】 不涉及
【案例】
优化前:
long int Fib(int n)
{
return (n <= 1) ? n : Fib(n-1) + Fib(n-2);
}
int Func(int a)
{
long int res = Fib(30);
return a + res;
}
以Arm GCC 7.3为例,编译器开-O2优化,生成的汇编代码如下:
Fib(int):
cmp r0, #1
push {r4, r5, r6, r7, r8, lr}
mov r5, #0
ble .L2
sub r7, r0, #2
bic r3, r7, #1
sub r6, r0, #3
sub r6, r6, r3
sub r4, r0, #1
.L3:
mov r0, r4
bl Fib(int)
sub r4, r4, #2
cmp r4, r6
add r5, r5, r0
bne .L3
and r0, r7, #1
.L2:
add r0, r5, r0
pop {r4, r5, r6, r7, r8, pc}
Func(int):
push {r4, lr}
mov r2, #29
mov r4, r0
mov r1, #0
.L9:
mov r0, r2
bl Fib(int)
sub r2, r2, #2
cmn r2, #1
add r1, r1, r0
bne .L9
add r0, r4, r1
pop {r4, pc}
说明:可以看出res的计算是调用了fib(30)在运行时得出的。
优化后:为fib()加上constexpr标识符来使编译器在编译器为fib(30)求值,代码如下:
constexpr long int Fib(int n)
{
return (n <= 1) ? n : Fib(n-1) + Fib(n-2);
}
int Func(int a)
{
constexpr long int res = Fib(30);
return a + res;
}
以Arm GCC 7.3为例,编译器开-O2优化,生成的汇编代码如下:
Func(int):
add r0, r0, #831488
add r0, r0, #552
bx lr
fib(30)的结果831488,在编译期就被求值,fib(30)在运行时直接使用了编译器计算出的运行时常量值。
父主题: C++语言