Wyjaśnienie
Niektóre kompilatory (zwłaszcza GCC) używają większej precyzji podczas oceny wyrażeń w czasie kompilacji. Jeśli wyrażenie zależy tylko od stałych danych wejściowych i literałów, może zostać ocenione w czasie kompilacji, nawet jeśli wyrażenie nie jest przypisane do zmiennej constexpr. To, czy tak się stanie, zależy od:
- Złożoność wyrażenia
- Próg używany przez kompilator jako wartość odcięcia podczas próby wykonania oceny czasu kompilacji
- Inne heurystyki używane w szczególnych przypadkach (np. Gdy pętle clang elides)
Jeśli wyrażenie jest jawnie podane, tak jak w pierwszym przypadku, ma ono mniejszą złożoność i kompilator prawdopodobnie oceni je w czasie kompilacji.
Podobnie, jeśli funkcja jest oznaczona jako wbudowana, kompilator z większym prawdopodobieństwem oceni ją w czasie kompilacji, ponieważ funkcje wbudowane podnoszą próg, przy którym może wystąpić ocena.
Wyższe poziomy optymalizacji również zwiększają ten próg, jak w przykładzie -Ofast, w którym wszystkie wyrażenia są oceniane jako prawda na gcc ze względu na wyższą precyzję obliczania czasu kompilacji.
Takie zachowanie możemy zaobserwować tutaj w eksploratorze kompilatora. Po skompilowaniu z -O1 tylko funkcja zaznaczona jako inline jest oceniana w czasie kompilacji, ale przy -O3 obie funkcje są oceniane w czasie kompilacji.
NB: W przykładach kompilatora-eksploratora używam printfzamiast tego iostream, ponieważ zmniejsza złożoność funkcji głównej, dzięki czemu efekt jest bardziej widoczny.
Wykazanie, że inlinenie ma to wpływu na ocenę środowiska uruchomieniowego
Możemy zapewnić, że żadne z wyrażeń nie jest oceniane w czasie kompilacji, uzyskując wartość ze standardowego wejścia, a kiedy to robimy, wszystkie 3 wyrażenia zwracają fałsz, jak pokazano tutaj: 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;
}
W przeciwieństwie do tego przykładu , w którym używamy tych samych ustawień kompilatora, ale podajemy wartość w czasie kompilacji, co skutkuje dokładniejszą oceną czasu kompilacji.