Namespaces
Variants

Constant expressions

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

Такие выражения могут использоваться в качестве константных аргументов шаблонов, размеров массивов и в других контекстах, требующих константных выражений, например.

int n = 1;
std::array<int, n> a1;  // Ошибка: "n" не является константным выражением
const int cn = 2;
std::array<int, cn> a2; // OK: "cn" является константным выражением

Содержание

Определение

Выражение, принадлежащее к любой из перечисленных ниже категорий константных выражений, является константным выражением .

Категории константных выражений C++98

Целочисленное константное выражение (C++98)

В следующих контекстах C++ требует выражения, вычисляемые в целочисленные или перечислимые константы:

Выражение, удовлетворяющее всем следующим условиям, является целочисленным константным выражением :

  • Оно использует только следующие сущности:
  • литералы арифметических типов
  • перечислители
  • переменные или статические данные-члены, удовлетворяющие всем следующим условиям:
  • Они квалифицированы как const.
  • Они не квалифицированы как volatile.
  • Они целочисленного или перечислимого типа.
  • Они инициализированы константными выражениями.
  • Оно не использует плавающие литералы, если они не явно преобразованы к целочисленным или перечислимым типам.
  • Оне не применяет преобразования к нецелочисленным и неперечислимым типам.
  • Оно не использует следующие сущности, кроме как в операндах sizeof :
  • функции
  • объекты классов
  • указатели
  • ссылки
  • оператор присваивания
  • оператор инкремента
  • оператор декремента
  • оператор вызова функции
  • оператор запятой

Другие категории константных выражений

Другие выражения считаются константными только для целей константной инициализации . Такое константное выражение должно быть одним из следующих:

  • выражение, вычисляемое в нулевое значение указателя
  • выражение, вычисляемое в нулевое значение указателя на член
  • арифметическое константное выражение
  • адресное константное выражение
  • ссылочное константное выражение
  • адресное константное выражение для полного типа объекта, плюс или минус целочисленное константное выражение
  • константное выражение указателя на член

Арифметическое константное выражение — это выражение, удовлетворяющее требованиям целочисленного константного выражения, со следующими исключениями:

  • Плавающие литералы могут использоваться без явного преобразования.
  • Могут применяться преобразования к плавающим типам.

Адресное константное выражение — это выражение указательного типа, удовлетворяющее всем следующим условиям:

  • явным использованием оператора взятия адреса
  • неявным использованием константного параметра шаблона указательного типа
  • использованием выражения массива или функционального типа
  • Выражение не вызывает никаких функций.
  • Выражение использует явные преобразования указателей (кроме dynamic_cast ) и следующие операторы без доступа к результирующему объекту:
  • оператор индексации
  • оператор разыменования
  • оператор взятия адреса
  • оператор доступа к члену
  • Если используется оператор индексации, один из его операндов является целочисленным константным выражением.

Ссылочное константное выражение — это выражение ссылочного типа, удовлетворяющее всем следующим условиям:

  • Ссылка обозначает объект статической продолжительности хранения, константный параметр шаблона ссылочного типа или функцию. Ссылка не обозначает член или базовый класс не-POD типа.
  • Выражение не вызывает никаких функций.
  • Выражение использует явные преобразования ссылок (кроме dynamic_cast ) и следующие операторы без доступа к результирующему объекту:
  • оператор индексации
  • оператор разыменования
  • оператор взятия адреса
  • оператор доступа к члену
  • Если используется оператор индексации, один из его операндов является целочисленным константным выражением.

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

(до C++11)

Следующие выражения в совокупности называются константными выражениями :

  • prvalue core constant expressions не-указательного literal type
  • lvalue core constant expressions, которые обозначают объекты с static storage duration или функции
  • prvalue core constant expressions указательного типа, которые вычисляются в одно из следующих значений:
  • адрес объекта со static storage duration
  • адрес функции
  • null pointer value
(since C++11)
(until C++14)

Следующие сущности являются допустимыми результатами константного выражения :

Константное выражение — это либо glvalue core constant expression , которое ссылается на сущность, являющуюся допустимым результатом константного выражения, либо prvalue core constant expression, значение которого удовлетворяет следующим ограничениям:

  • Если значение является объектом классового типа, каждый нестатический член данных ссылочного типа ссылается на сущность, которая является допустимым результатом константного выражения.
  • Если значение является объектом скалярного типа , оно не имеет неопределенного значения.
  • Если значение имеет указательный тип , оно является одним из следующих значений:
  • адрес объекта со статической продолжительностью хранения
  • адрес за пределами объекта со статической продолжительностью хранения
  • адрес не-immediate (since C++20) функции
  • нулевое значение указателя
  • Если значение имеет тип указателя на член-функцию, оно не обозначает immediate функцию.
(since C++20)
  • Если значение является объектом классового или массива, каждый подобъект удовлетворяет этим ограничениям для значения.
(since C++14)
(until C++26)

Константное выражение — это либо glvalue основное константное выражение , которое ссылается на объект или не- непосредственную функцию , либо prvalue основное константное выражение, значение которого удовлетворяет следующим ограничениям:

(начиная с C++26)

При определении того, является ли выражение константным выражением, copy elision предполагается не выполняемым.

Определение константных выражений в C++98 полностью находится в сворачиваемом блоке. Следующее описание применяется к C++11 и более поздним версиям C++.

Литеральный тип

Следующие типы в совокупности называются literal types :

  • Он имеет тривиальный деструктор (до C++20) constexpr деструктор (начиная с C++20) .
  • Все его нестатические невариантные члены данных и базовые классы являются не-volatile литеральными типами.
  • Он является одним из следующих типов:
(since C++17)
  • Не имеет вариантного члена.
  • Имеет хотя бы один вариантный член не-volatile литерального типа.
  • тип с хотя бы одним constexpr конструктором (шаблоном), который не является конструктором копирования или перемещения

Только объекты литеральных типов могут быть созданы в константном выражении.

Основное константное выражение

Основное константное выражение — это любое выражение, вычисление которого не должно включать вычисление ни одной из следующих языковых конструкций:

Конструкция языка Версия Документ(ы)
указатель this , за исключением случаев, когда он используется в constexpr функции , которая вычисляется как часть выражения, или когда появляется в неявном или явном выражении доступа к члену класса N2235
поток управления, проходящий через объявление блочной переменной со статической или поточной продолжительностью хранения , которая не является пригодной для использования в константных выражениях (начиная с C++23) P2242R3
  1. a function call expression that calls a function (or a constructor) that is not declared constexpr
    constexpr int n = std::numeric_limits<int>::max(); // OK: max() является constexpr
    constexpr int m = std::time(nullptr); // Ошибка: std::time() не является constexpr
  2. a function call to a constexpr function which is declared, but not defined
  3. a function call to a constexpr function/constructor template instantiation where the instantiation fails to satisfy constexpr функция/конструктор requirements.
  4. a function call to a constexpr virtual function, invoked on an object whose dynamic type is constexpr-unknown
  5. an expression that would exceed the implementation-defined limits
  6. an expression whose evaluation leads to any form of core language undefined или ошибочно (since C++26) behavior, except for any potential undefined behavior introduced by стандартные атрибуты .
    constexpr double d1 = 2.0 / 1.0; // OK
    constexpr double d2 = 2.0 / 0.0; // Ошибка: не определено
    constexpr int n = std::numeric_limits<int>::max() + 1; // Ошибка: переполнение
    int x, y, z[30];
    constexpr auto e1 = &y - &x;        // Ошибка: не определено
    constexpr auto e2 = &z[20] - &z[3]; // OK
    constexpr std::bitset<2> a; 
    constexpr bool b = a[2]; // UB, но не определено, будет ли обнаружено
  7. (до C++17) a лямбда-выражение
  8. an lvalue-to-rvalue неявное преобразование unless applied to...
    1. glvalue типа (возможно cv-квалифицированного) std::nullptr_t
    2. не-volatile glvalue литерального типа, который обозначает объект, пригодный для использования в константных выражениях
      int main()
      {
          const std::size_t tabsize = 50;
          int tab[tabsize]; // OK: tabsize является константным выражением
                            // потому что tabsize пригоден для использования в константных выражениях
                            // поскольку имеет const-квалифицированный целочисленный тип, и
                            // его инициализатор является константным инициализатором
          std::size_t n = 50;
          const std::size_t sz = n;
          int tab2[sz]; // Ошибка: sz не является константным выражением
                        // потому что sz не пригоден для использования в константных выражениях
                        // поскольку его инициализатор не был константным инициализатором
      }
    3. не-volatile glvalue литерального типа, который ссылается на не-volatile объект, время жизни которого началось в процессе вычисления данного выражения
  9. an lvalue-to-rvalue неявное преобразование or modification applied to a non-active member of a union or its subobject (even if it shares a common initial sequence with the active member)
  10. an lvalue-to-rvalue implicit conversion on an object значение которого неопределено
  11. an invocation of implicit copy/move constructor/assignment for a union whose active member is mutable (if any), with lifetime beginning outside the evaluation of this expression
  12. (до C++20) an assignment expression that would change the active member of a union
  13. conversion from указатель на void to a pointer-to-object type T* если только указатель не содержит нулевое значение указателя или не указывает на объект, тип которого подобен типу T (начиная с C++26)
  14. dynamic_cast операнд которого является glvalue, ссылающейся на объект, чей динамический тип является constexpr-неизвестным (since C++20)
  15. reinterpret_cast
  16. (до C++20) pseudo-destructor call
  17. (до C++14) an increment or a decrement operator
  18. (начиная с C++14) modification of an object, unless the object has non-volatile literal type and its lifetime began within the evaluation of the expression
    constexpr int incr(int& n)
    {
        return ++n;
    }
    constexpr int g(int k)
    {
        constexpr int x = incr(k); // Ошибка: incr(k) не является ядерным константным
                                   // выражением, потому что время жизни k
                                   // началось вне выражения incr(k)
        return x;
    }
    constexpr int h(int k)
    {
        int x = incr(k); // OK: x не требуется инициализировать
                         // ядерным константным выражением
        return x;
    }
    constexpr int y = h(1); // OK: инициализирует y значением 2
                            // h(1) является ядерным константным выражением, потому что
                            // время жизни k начинается внутри выражения h(1)
  19. (начиная с C++20) a destructor call or pseudo destructor call for an object whose lifetime did not begin within the evaluation of this expression
  20. a typeid expression applied to a glvalue of polymorphic type и этот glvalue ссылается на объект, динамический тип которого является constexpr-неизвестным (since C++20)
  21. a new выражение , если не выполняется одно из следующих условий: (since C++20)
    • Выбранная функция выделения памяти является заменяемой глобальной функцией выделения памяти, и выделенная память освобождается в процессе вычисления данного выражения.
    (since C++20)
    • Выбранная функция выделения памяти является невыделяющей формой с выделяемым типом T , и аргумент размещения удовлетворяет всем следующим условиям:
    • Он указывает на:
    • объект, тип которого подобен T , если T не является типом массива, или
    • первый элемент объекта типа, подобного T , если T является типом массива.
    • Он указывает на память, время жизни которой началось в процессе вычисления данного выражения.
    (since C++26)
  22. a delete выражение , если только он не освобождает область памяти, выделенную в ходе вычисления данного выражения (since C++20)
  23. (начиная с C++20) Coroutines: an выражение await or a yield-выражение
  24. (начиная с C++20) a трёхстороннее сравнение when the result is unspecified
  25. an equality or relational operator whose result is unspecified
  26. (до C++14) an assignment or a compound assignment operator
  27. (до C++26) выражение throw
  28. (начиная с C++26) создание объекта исключения, за исключением случая, когда объект исключения и все его неявные копии, созданные вызовами std::current_exception или std::rethrow_exception уничтожаются в процессе вычисления этого выражения
    constexpr void check(int i)
    {
        if (i < 0)
            throw i;
    {
    constexpr bool is_ok(int i)
    {
        try {
            check(i);
        } catch (...) {
            return false;
        }
        return true;
    {
    constexpr bool always_throw()
    {
        throw 12;
        return true;
    {
    static_assert(is_ok(5)); // OK
    static_assert(!is_ok(-1)); // OK начиная с C++26
    static_assert(always_throw()); // Ошибка: неперехваченное исключение
  29. asm-объявление asm-declaration
  30. вызов макроса va_arg
  31. оператор goto
  32. выражение dynamic_cast или typeid или выражение new expression (начиная с C++26) которое может сгенерировать исключение когда определение типа исключения недоступно (начиная с C++26)
  33. внутри лямбда-выражения - ссылка на this или на переменную, определенную вне этой лямбды, если эта ссылка является odr-использованием
    void g()
    {
        const int n = 0;
        constexpr int j = *&n; // OK: вне лямбда-выражения
        [=]
        {
            constexpr int i = n;   // OK: 'n' не odr-используется и не захватывается здесь
            constexpr int j = *&n; // Некорректно: '&n' было бы odr-использованием 'n'
        };
    }

    обратите внимание, что если odr-использование происходит в вызове функции замыкания, оно не ссылается на this или на охватывающую переменную, поскольку обращается к члену данных замыкания

    // OK: 'v' и 'm' odr-используются, но не встречаются в константном выражении
    // внутри вложенной лямбды
    auto monad = [](auto v){ return [=]{ return v; }; };
    auto bind = [](auto m){ return [=](auto fvm){ return fvm(m()); }; };
    // Допустимо иметь захваты автоматических объектов, созданных во время вычисления константного выражения
    static_assert(bind(monad(2))(monad)() == monad(2)());
    (начиная с C++17)

Дополнительные требования

Даже если выражение E не вычисляет ничего из перечисленного выше, определяется реализацией, является ли E core constant expression, если вычисление E привело бы к неопределённому поведению во время выполнения .

Даже если выражение E не вычисляет ничего из перечисленного выше, не определено, является ли E core constant expression, если вычисление E потребовало бы вычисления любого из следующего:

Для целей определения, является ли выражение ядерным константным выражением, вычисление тела функции-члена std:: allocator < T > игнорируется, если T является литеральным типом.

Для целей определения, является ли выражение ядерным константным выражением, вычисление вызова тривиального копирующего/перемещающего конструктора или копирующего/перемещающего оператора присваивания union считается копирующим/перемещающим активный член union, если таковой имеется.

Для целей определения, является ли выражение ядерным константным выражением, вычисление выражения-идентификатора, которое именует structured binding bd , имеет следующую семантику:

  • Если bd является lvalue, ссылающимся на объект, привязанный к изобретенной ссылке ref , поведение аналогично тому, как если бы была указана ref .
  • В противном случае, если bd именует элемент массива, поведение эквивалентно вычислению e [ i ] , где e — это имя переменной, инициализированной из инициализатора объявления structured binding, а i — индекс элемента, на который ссылается bd .
  • В противном случае, если bd именует член класса, поведение эквивалентно вычислению e. m , где e — это имя переменной, инициализированной из инициализатора объявления structured binding, а m — имя члена, на который ссылается bd .
(начиная с C++26)

При оценке выражения как основного константного выражения все выражения идентификаторов и использования * this , которые ссылаются на объект или ссылку, время жизни которых началось вне оценки выражения, рассматриваются как ссылающиеся на конкретный экземпляр этого объекта или ссылки, время жизни которого и всех подобъектов (включая все члены объединений) охватывает всю константную оценку.

  • Для такого объекта который не может использоваться в константных выражениях (начиная с C++20) , динамический тип объекта является constexpr-unknown .
  • Для такой ссылки которая не может использоваться в константных выражениях (начиная с C++20) , ссылка рассматривается как привязанная к неопределенному объекту ссылочного типа, время жизни которого и всех подобъектов включает всю константную оценку и чей динамический тип является constexpr-unknown.

Целочисленное константное выражение

Целочисленное константное выражение - это выражение целочисленного типа или типа неограниченного перечисления, неявно преобразованное в prvalue, где преобразованное выражение является ядерным константным выражением.

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

Преобразованное константное выражение

Преобразованное константное выражение типа T - это выражение, неявно преобразованное к типу T , где преобразованное выражение является константным выражением, и последовательность неявного преобразования содержит только:

(начиная с C++17)

И если происходит любое reference binding , оно может быть только direct binding .

Следующие контексты требуют конвертируемого константного выражения:

(начиная с C++14)
(начиная с C++26)

Контекстуально преобразованное константное выражение типа bool — это выражение, контекстуально преобразуемое в bool , где преобразуемое выражение является константным выражением, а последовательность преобразования содержит только указанные выше преобразования.

Следующие контексты требуют контекстно преобразованного константного выражения типа bool :

(до C++23)
(начиная с C++17)
(до C++23)
(начиная с C++20)


Составные сущности

Составные значения объекта obj определяются следующим образом:

Составные ссылки объекта obj включают следующие ссылки:

  • любые прямые члены obj , имеющие ссылочный тип
  • составные ссылки любых прямых подобъектов obj , кроме неактивных членов объединения

Составные значения и составные ссылки переменной var определяются следующим образом:

  • Если var объявляет объект, составными значениями и ссылками являются составные значения и ссылки этого объекта.
  • Если var объявляет ссылку, составной ссылкой является эта ссылка.

Для любой составной ссылки ref переменной var , если ref связана с временным объектом или его подобъектом, время жизни которого продлено до времени жизни ref , то составные значения и ссылки этого временного объекта также являются составными значениями и ссылками var , рекурсивно.

Сущности, представимые в constexpr

Объекты со статической продолжительностью хранения являются constexpr-ссылаемыми в любой точке программы.

Объект obj с автоматической продолжительностью хранения является constexpr-ссылаемым из точки P , если наименьшая область видимости , охватывающая переменную var , и наименьшая область видимости, охватывающая P , совпадают и представляют собой область видимости параметра функции, не связанную со списком параметров requires выражения , где var - это переменная, соответствующая полному объекту obj , или переменная, к времени жизни которой привязано время жизни obj , продленное .

Объект или ссылка x является constexpr-представимым в точке P , если выполняются все следующие условия:

  • Для каждого составного значения x , которое указывает на объект obj , obj является constexpr-ссылаемым из P .
  • Для каждого составного значения x , которое указывает за пределы объекта obj , obj является constexpr-ссылаемым из P .
  • Для каждой составной ссылки x , которая ссылается на объект obj , obj является constexpr-ссылаемым из P .
(начиная с C++26)

Сущности с константной инициализацией

Переменная или временный объект obj является константно-инициализированным , если выполняются все следующие условия:

  • Либо у неё есть инициализатор, либо её тип является константно-конструируемым по умолчанию .
  • Полное выражение её инициализации является константным выражением в контексте, требующем константное выражение, за исключением того, что если obj является объектом, то это полное выражение также может вызывать constexpr конструкторы для obj и её подобъектов, даже если эти объекты имеют типы не-литеральных классов.
(до C++26)

Переменная var является константно-инициализируемой , если выполняются все следующие условия:

  • Полное выражение её инициализации является константным выражением в контексте, требующем константное выражение, где все контрактные утверждения используют семантику оценки "ignore".
  • Сразу после инициализирующего объявления var , объект или ссылка, объявленные var , являются constexpr-представимыми.
  • Если объект или ссылка x , объявленные var , имеют статическую или потоковую продолжительность хранения, x является constexpr-представимым в ближайшей точке, чья непосредственная область видимости является областью видимости пространства имён, следующей за инициализирующим объявлением var .

Константно-инициализируемая переменная является константно-инициализированной , если либо у неё есть инициализатор, либо её тип является константно-конструируемым по умолчанию .

(начиная с C++26)

Применимо в константных выражениях

Переменная является потенциально-константной если она является constexpr переменной или имеет ссылочный тип, либо не-volatile const-квалифицированный целочисленный тип или тип перечисления.

Константно-инициализированная потенциально-константная переменная var является используемой в константных выражениях в точке P если её инициализирующее объявление D достижимо из P и выполняется любое из следующих условий:

  • var является constexpr переменной.
  • var не инициализирована TU-local значением.
  • P находится в той же единице трансляции, что и D .

Объект или ссылка являются пригодными для использования в константных выражениях в точке P , если они являются одной из следующих сущностей:

  • переменная, которая пригодна для использования в константных выражениях в P
  • временный объект не-volatile const-квалифицированного литерального типа, время жизни которого продлено до времени жизни переменной, пригодной для использования в константных выражениях в P
  • template parameter object
  • string literal object
  • неизменяемый подобъект любого из вышеперечисленных
  • ссылочный член любого из вышеперечисленных
(до C++26)

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

  • переменная, которая пригодна для использования в константных выражениях в P
  • временный объект не-volatile const-квалифицированного литерального типа, время жизни которого продлено до времени жизни переменной, пригодной для использования в константных выражениях в P
  • template parameter object
  • string literal object
  • неизменяемый подобъект любого из вышеперечисленных
  • ссылочный член любого из вышеперечисленных

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

(начиная с C++26)

Явно константно вычисляемые выражения

Следующие выражения (включая преобразования в целевой тип) являются явно константно-вычисляемыми :

Можно определить, происходит ли вычисление в явно константном контексте, с помощью std::is_constant_evaluated и if consteval (начиная с C++23) .

(начиная с C++20)

Функции и переменные, необходимые для константной оценки

Следующие выражения или преобразования являются потенциально константно вычисляемыми :

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

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

Определение функции по умолчанию и инстанцирование специализации шаблона функции или специализации шаблона переменной (since C++14) запускаются, если функция или переменная (since C++14) требуется для константного вычисления.

Постоянное подвыражение

Постоянное подвыражение — это выражение, вычисление которого в качестве подвыражения выражения e не препятствовало бы тому, чтобы e являлось ядерным константным выражением , при условии что e не является ни одним из следующих выражений:

(since C++20)

Примечания

Макрос тестирования возможностей Значение Стандарт Возможность
__cpp_constexpr_in_decltype 201711L (C++20)
(DR11)
Генерация определений функций и переменных, когда необходима для константного вычисления
__cpp_constexpr_dynamic_alloc 201907L (C++20) Операции для динамической продолжительности хранения в constexpr функциях
__cpp_constexpr 202306L (C++26) constexpr приведение из void * : в сторону constexpr стирания типа
202406L (C++26) constexpr размещающий new и new [ ]
__cpp_constexpr_exceptions 202411L (C++26) constexpr исключения: [1] , [2]

Пример

Отчеты о дефектах

Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение как опубликовано Корректное поведение
CWG 94 C++98 арифметические константные выражения не могли
включать переменные и статические члены данных
могут
CWG 366 C++98 выражения, содержащие строковые литералы
могли быть целочисленными константными выражениями
они не являются
CWG 457 C++98 выражения с участием volatile переменных
могли быть целочисленными константными выражениями
они не являются
CWG 1293 C++11 было неясно, можно ли использовать строковые литералы
в константных выражениях
их можно использовать
CWG 1311 C++11 volatile glvalues могли использоваться в константных выражениях запрещено
CWG 1312 C++11 reinterpret_cast запрещён в константных выражениях,
но приведение к и из void * может достичь того же эффекта
запрещённые преобразования
из типа cv void * в
тип указателя на объект
CWG 1313 C++11 неопределённое поведение было разрешено;
все операции вычитания указателей были запрещены
UB запрещено; вычитание указателей
на один массив разрешено
CWG 1405 C++11 для объектов, которые могут использоваться в константных выражениях,
их изменяемые подобъекты также могли использоваться
они не могут использоваться
CWG 1454 C++11 передача констант через constexpr
функции посредством ссылок не разрешалась
разрешено
CWG 1455 C++11 преобразованные константные выражения могли быть только prvalues могут быть lvalues
CWG 1456 C++11 адресное константное выражение не могло
обозначать адрес за последним элементом массива
разрешено
CWG 1535 C++11 выражение typeid с операндом полиморфного
типа класса не являлось core constant
выражением, даже если проверка времени выполнения не требуется
ограничение на операнд
применяется только к glvalue
полиморфных типов классов
CWG 1581 C++11 функции, необходимые для константной оценки,
не требовалось определять или инстанцировать
требуется
CWG 1613 C++11 константные выражения могли вычислять любую
odr-используемую ссылку внутри лямбда-выражений
некоторые ссылки не могли
быть вычислены
CWG 1694 C++11 привязка значения временного объекта к ссылке со статической
продолжительностью хранения была константным выражением
это не является
константным выражением
CWG 1872 C++11 константные выражения могли вызывать constexpr инстанциации шаблонов функций
которые не удовлетворяют требованиям constexpr функций
такие инстанциации
не могут быть вызваны
CWG 1952 C++11 неопределённое поведение стандартной библиотеки
требовало диагностики
не указано, требуется ли
их диагностика
CWG 2022 C++98 определение константного выражения может
зависеть от того, выполняется ли копирование
предполагать, что копирование
всегда выполняется
CWG 2126 C++11 константно инициализированные временные объекты с продлённым временем жизни для const-
квалифицированных литеральных типов не могли использоваться в константных выражениях
пригодны для использования
CWG 2129 C++11 целочисленные литералы не являлись константными выражениями являются
CWG 2167 C++11 ссылки не-члены, локальные для вычисления
делали вычисление не-constexpr
ссылки не-члены
разрешены
CWG 2278 C++98 решение CWG issue 2022 не было реализуемым предполагать, что копирующее исключение
никогда не выполняется
CWG 2299 C++14 было неясно, можно ли использовать макросы в <cstdarg>
при константной оценке
va_arg запрещён,
va_start не определён
CWG 2400 C++11 вызов constexpr виртуальной функции для объекта, не используемого
в константных выражениях и время жизни которого началось вне
выражения, содержащего вызов, может быть константным выражением
это не является
константным выражением
CWG 2490 C++20 вызовы (псевдо)деструкторов не имели
ограничений при константной оценке
ограничение добавлено
CWG 2552 C++23 при вычислении константного выражения ядра управляющий
поток не мог проходить через объявление неблочной переменной
может
CWG 2558 C++11 неопределённое значение может быть константным выражением не является константным выражением
CWG 2647 C++20 переменные типов с квалификатором volatile могут быть потенциально-константными они не являются таковыми
CWG 2763 C++11 нарушение [[ noreturn ]] не требовалось
обнаруживать во время константной оценки
требуется
CWG 2851 C++11 преобразованные константные выражения не
допускали преобразований с плавающей точкой
разрешить непредусматривающие сужение
преобразования с плавающей точкой
CWG 2907 C++11 константные выражения не могли применять
преобразования lvalue-to-rvalue к std::nullptr_t glvalues
могут применять такие
преобразования
CWG 2909 C++20 переменная без инициализатора может быть
константно-инициализирована только если её
инициализация по умолчанию приводит к выполнению некоторой инициализации
может быть константно-
инициализирована только если её тип является
константно-инициализируемым по умолчанию
CWG 2924 C++11
C++23
было не определено, является ли выражение, нарушающее
ограничения [[ noreturn ]] (C++11) или
[[ assume ]] (C++23), ядерным константным выражением
является
определяемым реализацией
P2280R4 C++11 вычисление выражения, содержащего идентификатор выражения
или * this который ссылается на объект или ссылку, время жизни
которого началось вне этого вычисления, не является константным выражением
может быть
константным выражением

Смотрите также

constexpr спецификатор (C++11) указывает, что значение переменной или функции может быть вычислено во время компиляции
(C++11) (устарело в C++17) (удалено в C++20)
проверяет, является ли тип литеральным типом
(шаблон класса)
Документация C для Константные выражения