Below is a recursive lambda expression that can compute the values of Fibonacci sequence both in runtime and during constant evaluation:
auto fib = [](this auto && f, auto && p) {
if ( p < 3 ) return 1;
decltype(+p) v{};
v = p - 2;
return f(v+1) + f(v);
};
// ok everywhere
static_assert( fib(1) == 1 );
static_assert( fib(2) == 1 );
static_assert( fib(3) == 2 );
static_assert( fib(4) == 3 );
static_assert( fib(5) == 5 );
static_assert( fib(6) == 8 );
static_assert( fib(7) == 13 );
static_assert( 20 <= fib(8) && fib(8) <= 21 );
// fails in MSVC
static_assert( fib(8) == 21 );
As far as I can see it works fine in GCC and Clang, but in Visual Studio it is so only for the first 7 elements, and fib(8)
is computed inaccurately resulting in a failure of static assertion. Online demo: https://gcc.godbolt.org/z/dMM6f16do
If the program is correct, why does it perform well for small numbers and does not work for larger ones (e.g. integer overflow, too many recursive calls)?
p
is just declared as anint
. – Unrealfib(8)
and agrees it's 21 as can be seen by modifying your example toreturn fib(8)
(gcc.godbolt.org/z/6h7YThT7M) – Hagueauto p
is also ok for MSVC, so... I agree, this is a bug in MSVC – Hagueconstexpr
, it is possible you reach it for MSVC. (constexpr
doesn't requires memoization). – Cockleboatconstexpr auto f8 = fib(8)
– Haguestatic_assert
is particularly poor in that it gives literally no information whatsoever... but the problem is taht it thinksfib(8)
is20
, not that it cannot evaluatefib(8)
: gcc.godbolt.org/z/zqTn5Yv4K – Unrealv
and justreturn f(p-1) + f(p-2);
in the natural way. (Code generation bugs are more common with awkward or unusual code.) – Chesterauto&&p
->auto p
orf(v)
->f(+v)
also makes it work. So maybe a bug with some constexpr tail call optimization? – Hole