Abaixo está uma expressão lambda recursiva que pode calcular os valores da sequência de Fibonacci tanto em tempo de execução quanto durante a avaliação constante:
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 );
Pelo que posso ver, funciona bem no GCC e no Clang, mas no Visual Studio funciona apenas para os primeiros 7 elementos e fib(8)
é calculado de forma imprecisa, resultando em uma falha na asserção estática. Demonstração online: https://gcc.godbolt.org/z/dMM6f16do
Se o programa estiver correto, por que ele funciona bem para números pequenos e não funciona para números maiores (por exemplo, estouro de inteiros, muitas chamadas recursivas)?
Este é definitivamente um bug do msvc (comportamento não conforme). Observe que msvc é impresso
21
quando imprimimosfib(8)
diretamente usandostd::cout
:Demonstração
Aqui está o relatório de bug enviado:
MSVC imprime resultados diferentes com base na chamada para a função constepxr é usada no contexto constexpr ou não