我正在尝试constexpr:
#include <iostream>
constexpr long long fibonacci(const int x)
{
return x <= 1 ? 1 : fibonacci(x - 1) + fibonacci(x - 2);
}
int main()
{
const long long lol = fibonacci(500);
std::cout << lol << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
所以我想lol在编译时计算:
toogy@stewie
» g++ -std=c++14 -g src/test.cc -o test.out
toogy@stewie
» ./test.out
4859788740867454402
Run Code Online (Sandbox Code Playgroud)
它的工作非常好g++.在编译时,它甚至会进行一些记忆,优化这种糟糕的斐波纳契功能,然后fibonacci(500)立即进行计算.
然后我尝试clang++:
toogy@stewie
» clang++ -std=c++1y -g src/test.cc -o test.out
toogy@stewie
» ./test.out
... very long
Run Code Online (Sandbox Code Playgroud)
lol不是在编译时由clang++(证明gdb)计算的.为什么?
它击中了clang的最大递归深度.您可以lol通过编译强制在编译时进行评估constexpr,即:
constexpr long long lol = fibonacci(500);
Run Code Online (Sandbox Code Playgroud)
这样做和编译clang++ -std=c++11 t.cpp会给出错误:
t.cpp:10:25: error: constexpr variable 'lol' must be initialized by a constant
expression
constexpr long long lol = fib(500);
^ ~~~~~~~~
t.cpp:4:1: note: constexpr evaluation hit maximum step limit; possible infinite
loop?
{
^
t.cpp:5:38: note: in call to 'fib(4)'
return x <= 1 ? 1 : fib(x - 1) + fib(x - 2);
^
t.cpp:5:25: note: in call to 'fib(6)'
return x <= 1 ? 1 : fib(x - 1) + fib(x - 2);
^
t.cpp:5:38: note: in call to 'fib(7)'
return x <= 1 ? 1 : fib(x - 1) + fib(x - 2);
^
t.cpp:5:25: note: in call to 'fib(9)'
return x <= 1 ? 1 : fib(x - 1) + fib(x - 2);
^
t.cpp:5:25: note: in call to 'fib(10)'
t.cpp:5:25: note: (skipping 480 calls in backtrace; use
-fconstexpr-backtrace-limit=0 to see all)
t.cpp:5:25: note: in call to 'fib(496)'
t.cpp:5:25: note: in call to 'fib(497)'
t.cpp:5:25: note: in call to 'fib(498)'
t.cpp:5:25: note: in call to 'fib(499)'
t.cpp:10:31: note: in call to 'fib(500)'
constexpr long long lol = fib(500);
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
Clang不能(使用默认的编译器标志;虽然我仍然无法使用-fconstexpr-depth=1000000000(那是10亿)fibonacci(500)编译)在编译时进行评估,因此它在运行时使用您发布的代码进行评估.当@Streppel链接到时,可以使用-fconstexpr-depth=N编译器标志增加常量表达式的最大递归深度.
但是,第500个斐波那契数字是巨大的*,所以这肯定会溢出,这对于有符号整数来说是未定义的行为(所以所有的赌注都是关闭的,真的).(但是如果使用模板元编程,你可以这样做)
*在105位数巨大:139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125