为什么在运行时而不是在编译时使用constexpr初始化变量

据我了解,关键字constexpr告诉编译器表达式的计算可以在编译时发生。具体来说,constexpr在变量上意味着可以在编译时评估变量的值,而constexpr在函数上意味着可以在编译时调用该函数并评估其返回值。如果函数在运行时被调用,它只是作为一个普通函数。

今天,我写了一段代码来尝试使用constexpr

#include <iostream>

using namespace std;

constexpr long int fib(int n)
{
    return (n <= 1)? n : fib(n-1) + fib(n-2);
}

int main ()
{
    constexpr long int res = fib(32);
    // const long int res = fib(32);
    
    cout << res << endl;
    return 0;
}

我原以为代码的编译会花费很多时间,但我错了。编译只用了0.0290s:

$ time g++ test.cpp
real    0m0.290s
user    0m0.252s
sys     0m0.035s

但是如果我constexpr long int res = fib(32);换成const long int res = fib(32);,出乎我的意料,它在编译上花费了更多的时间:

$ time g++ test.cpp
real    0m5.830s
user    0m5.568s
sys     0m0.233s

总之,这似乎 const使函数fib(32)在编译时被评估,但constexpr让它在运行时被评估。我真的很困惑。

我的系统:Ubuntu 18.04

我的 gcc: g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

回答

通过检查生成的程序集,我们可以确认G++ 7.5在两种情况下都fib(32)在编译时计算了值:

    movl    $2178309, %esi

G++constexpr如此快速地评估上下文的原因是它在评估和上下文时执行的记忆。constexprtemplate

记忆化通过将其降低到 O(N) 复杂度来完全消除斐波那契计算复杂度。

那么为什么非constexpr评估会慢这么多呢?我认为这是优化器中的错误/缺点。如果我尝试使用 G++ 8.1 或更高版本,编译时间没有区别,所以大概已经解决了。


以上是为什么在运行时而不是在编译时使用constexpr初始化变量的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>