← Назад к вопросам

Что делает ключевое слово constexpr?

2.2 Middle🔥 241 комментариев
#Язык C++

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что делает ключевое слово constexpr?

constexpr — это ключевое слово в C++, которое сообщает компилятору, что функция или переменная может быть вычислена во время компиляции. Это один из самых мощных инструментов для оптимизации и безопасности типов в современном C++.

Основное значение

constexpr означает две вещи одновременно:

  1. Значение известно на этапе компиляции (может быть вычислено компилятором)
  2. Значение неизменяемо (как const)

constexpr переменные

// Обычная const — значение может быть на время выполнения
const int a = std::rand();  // Вычисляется в runtime

// constexpr — должно быть на этапе компиляции
constexpr int b = 10;  // OK - вычисляется на этапе компиляции
constexpr int c = std::rand();  // ОШИБКА - std::rand() не constexpr

// constexpr может использоваться как размер массива
constexpr int SIZE = 100;
int arr[SIZE];  // OK - SIZE известно на этапе компиляции

int len = 100;
int arr2[len];  // ОШИБКА - len не известна на этапе компиляции

constexpr функции

Функция может работать как на этапе компиляции, так и во время выполнения:

// Простая constexpr функция
constexpr int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

// Вычисляется на этапе компиляции
constexpr int fact5 = factorial(5);  // 120 (в момент компиляции)

// Вычисляется во время выполнения
int n = 5;
int result = factorial(n);  // 120 (в runtime, обычная функция)

// Пример: вычисление на этапе компиляции
int arr[factorial(5)];  // Массив размером 120 - работает!

Ограничения constexpr функций

Функция может быть constexpr только если:

  1. Состоит из простых операций (арифметика, условия, циклы)
  2. Не содержит статических переменных
  3. Не содержит goto и меток
  4. Все параметры и возвращаемое значение "литеральные" типы (int, double, но не std::string до C++20)
// OK - простая функция
constexpr int add(int a, int b) {
    return a + b;
}

// OK - циклы разрешены (C++14)
constexpr int sum(int n) {
    int result = 0;
    for (int i = 1; i <= n; i++) {
        result += i;
    }
    return result;
}

// ОШИБКА - не может быть constexpr
constexpr std::string greet(std::string name) {  // ОШИБКА до C++20
    return "Hello, " + name;
}

Примеры использования

Пример 1: Таблица квадратов во время компиляции

constexpr int square(int x) {
    return x * x;
}

// Массив инициализируется во время компиляции
const int squares[] = {
    square(1),   // 1
    square(2),   // 4
    square(3),   // 9
    square(4),   // 16
    square(5)    // 25
};
// После компиляции это просто: [1, 4, 9, 16, 25]

Пример 2: Константы для шаблонов

constexpr int MAX_BUFFER_SIZE = 1024;

template<int N>
class Buffer {
    char data[N];  // N должно быть известно на этапе компиляции
};

Buffer<MAX_BUFFER_SIZE> buf;  // OK

int size = 512;
Buffer<size> buf2;  // ОШИБКА - size не constexpr

Пример 3: Оптимизация производительности

// Без constexpr - вычисляется каждый раз в runtime
int power(int base, int exp) {
    int result = 1;
    for (int i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

int main() {
    int p = power(2, 10);  // 1024 операций в runtime
}

// С constexpr - вычисляется один раз на этапе компиляции
constexpr int power(int base, int exp) {
    int result = 1;
    for (int i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

int main() {
    constexpr int p = power(2, 10);  // Вычислено: p = 1024 (нет кода в бинарнике)
}

constexpr vs const

Характеристикаconstconstexpr
Может быть вычислено на этапе компиляцииНетДа
Может быть вычислено во время выполненияДаНет (для constexpr значения)
Используется как размер массиваНетДа
В шаблонахНетДа
Синтаксис прощеДаНет
const int a = std::rand();      // OK - вычисляется в runtime
const int b = computeValue();   // OK - вычисляется в runtime

constexpr int c = 10;          // OK - известно на этапе компиляции
constexpr int d = factorial(5); // OK - factorial может быть вычислена на этапе компиляции

C++20 и далее

C++20 расширил возможности constexpr:

  • constexpr std::string и контейнеры
  • constexpr new/delete (правда ограниченно)
  • std::is_constant_evaluated() — проверить, выполняется ли код на этапе компиляции
// C++20
constexpr std::string greet() {
    return "Hello";  // Теперь работает!
}

Выводы

constexpr — это инструмент для:

  • Производительности — вычисление один раз на этапе компиляции
  • Безопасности типов — гарантирует, что значение известно заранее
  • Zero-cost абстракции — нет затрат во время выполнения

Оно требует дополнительных усилий для написания, но даёт гарантии и оптимизации, которые невозможны с обычным кодом.