В версии C++11 появились константные выражения constexpr
(constant expression) - этот модификатор подсказывает компилятору, что сущность может быть выполнена и вычислена на этапе компиляции, то есть буквально силами компилятора, а не скомпилированной и запущенной программы. Посмотрим, как оно работает.
Когда код выполняется компилятором, то это происходит в compile time - на этапе компиляции. Если код выполняется непосредственно во время работы программы - это называется runtime, по-русски так и называют - в рантайме
Константы и выражения #
constexpr
-выражение может содержать только члены, значение которых известно на момент компиляции, и операции между ними:
- Целые и
float
литералы (непосредственно цифры в коде),bool
,nullptr
, строковые литералы ("строки"
) - Другие
constexpr
-константы - Вызов (результат)
constexpr
-функций и методов классов - Численные параметры шаблонов
#define
-константы с такими же правилами- Математические, логические и бинарные операции
Такое выражение может быть присвоено constexpr
константе:
#define MY_CONST 3.14f
constexpr int myconstexpr = 5;
constexpr int cnstFunc() {
return 10;
}
constexpr int myconst = myconstexpr + 123 * MY_CONST * cnstFunc();
Отличие от обычной константы состоит в том, что выражение в любом случае вычисляется компилятором, т.е. даже не попадает в программу после компиляции - только результат в виде числа. Современные IDE, например VS Code (урок), подсвечивают результат, если навести курсор на имя константы - очень удобно, можно отлаживать некоторые конструкции даже не компилируя программу, не говоря о том, чтобы её запускать.
Функции #
constexpr
функция может быть вычислена компилятором, если вызывается с известными на момент компиляции аргументами. В то же время, она может вызываться и выполняться как обычная функция в рантайме.
В разных версиях C++ есть разные ограничения на сам код таких функций: чем старше версия - тем меньше ограничений. Рассмотрим версию C++11, т.к. в основном она используется по умолчанию для разработки под МК (AVR, ESP) на момент написания урока. constexpr
функция:
- Должна содержать только один
return
- Не может содержать
for
,while
,do
,if
,switch
,goto
- Не может содержать вызовов других не-
constexpr
функций - Не может создавать локальные переменные
- Не может работать с динамической памятью (
new
,delete
)
А что же тогда она вообще может и как с этим работать? Можно:
- Вызывать другие
constexpr
функции и классы - Использовать рекурсивный вызов вместо циклов
- Использовать параметры функции вместо локальных переменных
- Использовать тернарный оператор для ветвления
Чтобы писать более сложный код в таких ограниченных условиях, нужно хорошо освоить рекурсивные конструкции. Например, перепишем для constexpr
показанные в том уроке функции. По сути, нужно было просто заменить условие на тернарник:
constexpr int factorial(int n) {
return n ? (n * factorial(n - 1)) : 1;
}
constexpr int power(int base, int exp) {
return exp ? (base * power(base, exp - 1)) : 1;
}
Полезный инструмент, и становится ещё более полезным в свежих версиях C++. Например вот проект constexpr CSV парсера на C++17.
Возможности в версиях #
Возможность | C++11 | C++14 | C++17 | C++20 | C++23 |
---|---|---|---|---|---|
Простые выражения (арифметика, return ) |
✅ | ✅ | ✅ | ✅ | ✅ |
Вызовы других constexpr функций |
✅ | ✅ | ✅ | ✅ | ✅ |
Шаблонные constexpr функции |
✅ | ✅ | ✅ | ✅ | ✅ |
Использование классов с constexpr членами |
✅ | ✅ | ✅ | ✅ | ✅ |
Локальные переменные | ❌ | ✅ | ✅ | ✅ | ✅ |
Условные операторы (if , switch ) |
❌ | ✅ | ✅ | ✅ | ✅ |
Циклы (for , while , do ) |
❌ | ✅ | ✅ | ✅ | ✅ |
Вложенные функции | ❌ | ✅ | ✅ | ✅ | ✅ |
Использование try /catch |
❌ | ❌ | ❌ | ✅ | ✅ |
Динамическое выделение памяти (new , delete ) |
❌ | ❌ | ❌ | ✅ | ✅ |
Использование виртуальных функций | ❌ | ❌ | ❌ | ✅ | ✅ |
Работа с std::vector , std::string |
❌ | ❌ | ❌ | ❌ | ✅ |

Полезные страницы #
- Набор GyverKIT – наш большой стартовый набор Arduino, продаётся в России
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту ([email protected])
- Поддержать автора за работу над уроками