Перейти к содержанию

Последнее обновление:2026-10-12

C++ всё семейство const

План

  • const
  • constexpr
  • C++20
  • consteval
  • constinit

Примечание: все примеры кода из этой статьи размещены в 知识星球 (Zhishi Xingqiu).

1.const

const — одно из первых ключевых слов, с которыми мы сталкиваемся при изучении C++/C; обычно оно используется как cv-qualifier и означает, что объект неизменяем. Оно не гарантирует вычисление во время компиляции; конкретный момент вычисления определяется компилятором. Например:

const int a = 1; // 编译时
const auto x = getdata(); // 运行时

const иногда можно использовать в константных выражениях времени компиляции, но есть исключения, например:

const double count_1 = 3.3;
std::array<double, static_cast<int>(count_1)> moreDoubles1 {1.1, 2.2, 3.3};

В этом случае возникнет ошибка: the value of 'count_1' is not usable in a constant expression

А вот так — всё в порядке:

const int count = 3;
std::array<double, count> doubles {1.1, 2.2, 3.3};

Суть в вычислении значения выражения во время компиляции, поэтому в C++11 появился constexpr.

2.constexpr

constexpr позволяет указать, что значение переменной может встречаться в константном выражении; достаточно заменить const на constexpr в предыдущем примере, и всё заработает.

constexpr double count_2 = 3.3;
std::array<double, static_cast<int>(count_2)> moreDoubles2 {1.1, 2.2, 3.3}; 

constexpr не обязательно выполняется только во время компиляции. Его исконный смысл — возможность вычисления во время компиляции, но если constexpr-переменная или функция используется во время выполнения, она может выполняться и в рантайме.

Например: result1 и result2 совершенно различны — result1 вычисляется во время компиляции, а result2 во время выполнения. Вопрос на засыпку: знаете ли вы, почему?

Так что функция, помеченная constexpr, не обязательно вычисляется во время компиляции.

constexpr int compileTimeSum(int a, int b) {
    return a + b;
}

int main() {
    constexpr int result1 = compileTimeSum(3, 5); 
    int x = 10;
    int result2 = compileTimeSum(x, 20);  
    return 0;
}

Так кто же это гарантирует? Тогда на сцену выходит C++20.

3.C++20

3.1 consteval

consteval решает описанную выше проблему: он применим только к функциям и принуждает все вызовы выполняться во время компиляции. Что произойдёт с result2, если мы заменим в примере выше constexpr на consteval?

Возникнет ошибка: call to consteval function 'compileTimeSum(x, 20)' is not a constant expression

consteval int compileTimeSum(int a, int b) {
    return a + b;
}

int main() {
    constexpr int result1 = compileTimeSum(3, 5); 
    int x = 10;
    int result2 = compileTimeSum(x, 20);  
    return 0;
}

Если применить consteval к переменной, тоже будет ошибка: error: a variable cannot be declared 'consteval'.

https://en.cppreference.com/w/cpp/language/consteval

3.2 constinit

constinit позволяет принудительно выполнить константную инициализацию статических или локальных для потока переменных.

  • Нельзя использовать вместе с constexpr и consteval
  • Не является спецификатором типа, его роль — assert
  • Гарантирует статическую инициализацию переменной
  • Применим только к static или thread_local

Например, следующий код не скомпилируется: error: 'constinit' can only be applied to a variable with static or thread storage duration

constinit int a = 100;  
int main() {  
      ++a; 
      constinit auto b = 100;  // error
      // b has thread storage duration
      constinit thread_local auto b = 100;
}

Похожие темы

Комментарии