Объяснение
Некоторые компиляторы (особенно GCC) используют более высокую точность при оценке выражений во время компиляции. Если выражение зависит только от константных входов и литералов, оно может быть вычислено во время компиляции, даже если выражение не присвоено переменной constexpr. Произойдет это или нет, зависит от:
- Сложность выражения
- Порог, который компилятор использует в качестве отсечки при попытке выполнить оценку времени компиляции.
- Другие эвристики, используемые в особых случаях (например, когда clang удаляет петли)
Если выражение указано явно, как в первом случае, оно имеет меньшую сложность, и компилятор, скорее всего, оценит его во время компиляции.
Точно так же, если функция помечена как встроенная, компилятор с большей вероятностью оценит ее во время компиляции, поскольку встроенные функции повышают порог, при котором может произойти оценка.
Более высокие уровни оптимизации также увеличивают этот порог, как в примере -Ofast, где все выражения оцениваются как истинные в gcc из-за более высокой точности оценки времени компиляции.
Мы можем наблюдать это поведение здесь, в проводнике компилятора. При компиляции с -O1 только функция, помеченная как встроенная, оценивается во время компиляции, но при -O3 обе функции оцениваются во время компиляции.
NB: в примерах компилятора-проводника я использую printfвместо этого iostream, потому что он снижает сложность основной функции, делая эффект более заметным.
Демонстрация, inlineне влияющая на оценку времени выполнения
Мы можем гарантировать, что ни одно из выражений не вычисляется во время компиляции, получая значение из стандартного ввода, и когда мы это делаем, все 3 выражения возвращают false, как показано здесь: 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;
}
В отличие от этого примера , где мы используем те же настройки компилятора, но предоставляем значение во время компиляции, что приводит к более точной оценке времени компиляции.