Explicação
Alguns compiladores (notavelmente GCC) usam maior precisão ao avaliar expressões em tempo de compilação. Se uma expressão depende apenas de entradas e literais constantes, ela pode ser avaliada em tempo de compilação, mesmo se a expressão não for atribuída a uma variável constexpr. Se isso ocorre ou não depende de:
- A complexidade da expressão
- O limite que o compilador usa como um corte ao tentar realizar a avaliação do tempo de compilação
- Outras heurísticas usadas em casos especiais (como quando clang elides loops)
Se uma expressão for fornecida explicitamente, como no primeiro caso, ela terá uma complexidade menor e o compilador provavelmente irá avaliá-la no momento da compilação.
Da mesma forma, se uma função for marcada em linha, é mais provável que o compilador avalie-a em tempo de compilação porque as funções em linha aumentam o limite no qual a avaliação pode ocorrer.
Níveis de otimização mais altos também aumentam esse limite, como no exemplo -Ofast, onde todas as expressões são avaliadas como verdadeiras no gcc devido à avaliação de tempo de compilação de maior precisão.
Podemos observar esse comportamento aqui no compilador explorer. Quando compilado com -O1, apenas a função marcada inline é avaliada em tempo de compilação, mas em -O3 ambas as funções são avaliadas em tempo de compilação.
NB: Nos exemplos do compilador-explorador, eu uso printf iostream porque reduz a complexidade da função principal, tornando o efeito mais visível.
Demonstrando que inline não afeta a avaliação do tempo de execução
Podemos garantir que nenhuma das expressões seja avaliada em tempo de compilação obtendo o valor da entrada padrão e, quando fazemos isso, todas as 3 expressões retornam falso, conforme demonstrado aqui: https://ideone.com/QZbv6X
#include <cmath>
#include <iostream>
bool is_cube(double r)
{
return floor(cbrt(r)) == cbrt(r);
}
bool inline is_cube_inline(double r)
{
return floor(cbrt(r)) == cbrt(r);
}
int main()
{
double value;
std::cin >> value;
std::cout << (floor(cbrt(value)) == cbrt(value)) << std::endl;
std::cout << (is_cube(value)) << std::endl;
std::cout << (is_cube_inline(value)) << std::endl;
}
Compare com este exemplo , onde usamos as mesmas configurações do compilador, mas fornecemos o valor em tempo de compilação, resultando em uma avaliação de tempo de compilação de maior precisão.