Ответ
В современном C++ для гарантии вычислений во время компиляции используются constexpr (C++11/14), consteval (C++20) и static_assert для проверки.
1. Использование constexpr и static_assert:
Если constexpr-функция не может быть вычислена на этапе компиляции, код не скомпилируется.
constexpr int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; ++i) { // Циклы разрешены в constexpr с C++14
result *= i;
}
return result;
}
// Проверка во время компиляции
static_assert(factorial(5) == 120, "Compile-time computation failed");
static_assert(factorial(0) == 1);
int main() {
constexpr int compile_time_value = factorial(6); // Вычисляется при компиляции
int runtime_value = factorial(10); // Может быть вычислено и во время выполнения
return 0;
}
2. Использование consteval (C++20):
Функции, помеченные как consteval, должны давать результат на этапе компиляции. Вызов такой функции с аргументами, известными только во время выполнения, приведёт к ошибке компиляции.
consteval int square(int x) {
return x * x;
}
static_assert(square(9) == 81); // OK
int main() {
constexpr int a = square(5); // OK
int runtime_input = 7;
// int b = square(runtime_input); // Ошибка компиляции: аргумент не является константным выражением
return 0;
}
3. Проверка типов и условий на этапе компиляции с if constexpr:
template<typename T>
constexpr auto getTypeSize() {
if constexpr (std::is_integral_v<T>) {
return sizeof(T);
} else {
// Этот branch отбрасывается на этапе компиляции для целочисленных типов
return 0;
}
}
static_assert(getTypeSize<int>() == 4); // Проверка для 32-битной платформы
Практическое применение:
- Вычисления констант: Размеры массивов, математические константы.
- Метапрограммирование: Генерация типов, проверка условий.
- Оптимизация: Вынос вычислений из времени выполнения, если аргументы известны при компиляции.
Если static_assert срабатывает, вы получаете ошибку компиляции — это и есть доказательство, что проверка (или вычисление) произошла на этапе компиляции.