История вопроса
C++ изначально поддерживал только макросы (#define) и константы (const). Однако для целей определения значений во время компиляции этого было недостаточно. В C++11 введено ключевое слово constexpr, позволяющее вычислять значения ещё на этапе компиляции, а не только во время выполнения программы.
Проблема
До появления constexpr многие задачи приходилось решать либо при помощи макросов (грубый текстовый подстановщик без типобезопасности), либо с помощью const, который не всегда гарантировал выполнение выражения на этапе компиляции. Это затрудняло оптимизацию программы и привело к менее предсказуемому поведению.
Решение
constexpr гарантирует компилятору, что объявленное выражение обязательно будет вычислено при компиляции, если это возможно. Это используется для объявления функций, переменных и даже конструкторов и методов классов, которые безопасно и эффективно вычисляются при компиляции.
Пример кода:
constexpr int Square(int x) { return x * x; } constexpr int size = Square(5); // size вычисляется на этапе компиляции const int arr[size] = {}; // можно использовать в качестве размера массива
Ключевые особенности:
Можно ли использовать любую функцию в качестве constexpr?
Нет. Функция должна соответствовать ряду ограничений: быть достаточно простой, содержать одну return-строку (до C++14) или только константно-вычисляемый код (с C++14 и выше).
constexpr int f(int x) { return x + 2; } // ok constexpr int g(int x) { int y = x + 2; return y; } // до C++14: не компилируется! после — можно
Могут ли все constexpr переменные вычисляться во время компиляции?
Нет. Если при инициализации используется не-константное значение или выражение не удаётся вычислить при компиляции, будет ошибка.
int val; // constexpr int x = f(val); // Ошибка: val не инициализирован!
В чём разница между constexpr и const?
const гарантирует только невозможность изменения, но не гарантирует вычисление при компиляции. constexpr требует вычислить значение во время компиляции (если возможно).
const int x = time(nullptr); // ок, но вычисляется во время выполнения constexpr int y = 42; // ок, вычисляется во время компиляции
Разработчик использует #define PI 3.14 для всех вычислений площади круга.
Плюсы:
Минусы:
Разработчик использует constexpr double PI = 3.141592653589793; и шаблонные constexpr-функции для вычислений.
Плюсы:
Минусы: