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

Сталкивался ли с ключевым словом constexpr

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

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

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

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

constexpr: вычисления на этапе компиляции

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

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

constexpr означает: "Эта функция или переменная могут быть вычислены на этапе компиляции". Компилятор будет стараться вычислить значение во время компиляции, если это возможно.

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

1. constexpr переменные

// Константа, вычисленная на этапе компиляции
constexpr int BUFFER_SIZE = 1024;
constexpr double PI = 3.14159;

// Это будет вычислено на этапе компиляции, не runtime
constexpr int ARRAY_SIZE = 10 * 1024;  // = 10240

2. constexpr функции

// Факториал, вычисленный на этапе компиляции
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

// Использование:
constexpr int fact5 = factorial(5);  // 120 — вычислено во время компиляции!
int result = factorial(10);             // Может быть вычислено или во время компиляции, или runtime

3. Практический пример: таблица быстрого доступа

constexpr int fibonacci(int n) {
    return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}

// Таблица вычисляется во время компиляции!
struct FibonacciLookup {
    int values[20];
    constexpr FibonacciLookup() : values{} {
        for (int i = 0; i < 20; ++i) {
            values[i] = fibonacci(i);
        }
    }
};

constexpr FibonacciLookup fib_table;  // Вся таблица в готовом виде!

Преимущества constexpr

1. Производительность

  • Вычисления происходят на этапе компиляции
  • Runtime почти мгновенный доступ
  • Идеально для встроенных систем с жёсткими ограничениями

2. Размер кода

// БЕЗ constexpr — код генерируется для каждого вызова
int arr[getSize()];  // Ошибка! размер должен быть compile-time константой

// С constexpr — всё работает
constexpr int arr[getSize()];  // Работает если getSize() constexpr

3. Compile-time проверки

template<int Size>
class StaticBuffer {
    std::array<char, Size> data;
};

// С constexpr можно делать сложные проверки на этапе компиляции
constexpr bool isValidSize(int sz) {
    return sz > 0 && sz <= 1000000;
}

static_assert(isValidSize(1024), "Invalid size");  // Проверка на компиляции!

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

В C++17 и раньше constexpr функции имели ограничения:

  • Одно возвращаемое значение: return ...;
  • Нельзя изменять глобальные переменные
  • Нельзя использовать goto
  • Нельзя иметь static переменные
// ❌ Не компилируется в C++17
constexpr int bad(int n) {
    static int counter = 0;  // Ошибка!
    return counter++;
}

// ✅ OK в C++20+
constexpr int good(int n) {
    int counter = 0;
    for (int i = 0; i < n; ++i) {
        counter++;
    }
    return counter;
}

C++20: if constexpr

Одна из самых мощных фишек — условная компиляция:

template<typename T>
void process(T value) {
    if constexpr (std::is_integral_v<T>) {
        // Этот код генерируется только для целых чисел
        std::cout << "Integer: " << value << std::endl;
    } else if constexpr (std::is_floating_point_v<T>) {
        // Этот код только для float/double
        std::cout << "Float: " << std::fixed << value << std::endl;
    }
    // Неподходящий код вообще не компилируется!
}

Реальные примеры из production

1. Валидация конфигураций

struct Config {
    static constexpr size_t MAX_CONNECTIONS = 1000;
    static constexpr size_t BUFFER_SIZE = 4096;
};

static_assert(Config::BUFFER_SIZE >= 512, "Buffer too small");

2. Побитовые операции

constexpr uint32_t rotateLeft(uint32_t val, int shift) {
    return (val << shift) | (val >> (32 - shift));
}

constexpr uint32_t MAGIC = rotateLeft(0x12345678, 4);  // Computed at compile time

3. Строковая обработка (C++20)

std::array<std::string_view, 3> split(std::string_view str) {
    // Можно парсить строки на этапе компиляции!
}

Когда использовать constexpr

  • Таблицы предвычисленных значений (LUT, lookup tables)
  • Параметры конфигурации известные на этапе компиляции
  • Математические функции (факториал, fibonacci, степени)
  • Валидация constexpr констант через static_assert
  • Оптимизация hot path критичного кода
  • Метапрограммирование и template specialization

Итог

constexpr — это не просто оптимизация, это инструмент для перемещения вычислений с runtime на compile-time. В сочетании с if constexpr и static_assert это позволяет писать максимально оптимальный и безопасный код. Для backend разработчика, работающего с высоконагруженными системами, это критически важная техника.

Сталкивался ли с ключевым словом constexpr | PrepBro