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)?
This is definitely a msvc bug(non-conformant behavior). Note that msvc prints 21
when we print fib(8)
directly using std::cout
:
int main()
{
std::cout << fib(8) << "\n"; //msvc prints 21
constexpr int i = fib(8);
std::cout << i; //msvc prints 20
}
Here is the submitted bug report:
MSVC prints different result based on call to constepxr function is used in constexpr context or not