Подтвердить что ты не робот

Int a = 1, является || 1 постоянное выражение?

N4527 5.20 [expr.const] p5

Постоянное выражение представляет собой либо выражение константы ядра glvalue, значение которого относится к объекту, который является разрешенный результат постоянного выражения (как определено ниже) или выражение постоянной константы prvalue, чье value - это объект, где для этого объекта и его подобъектов:

- каждый нестатический элемент данных ссылочного типа относится к объекту, который является допустимым результатом постоянного выражения, и

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

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

void foo(){
    int a = 1;
    int b[a || 1]{};//ok in gcc 5.1.0, error in clang 3.8.0
    static_assert(a || 1,"");//ok in gcc 5.1.0, error in clang 3.8.0
    switch(1){
        case a || 1://ok in gcc 5.1.0, error in clang 3.8.0
            ;
        }
}

Является a || 1 a константным выражением?


N4527 5.20 [expr.const] p2

Условное выражение e является выражением постоянной константы, если оценка e, следуя правилам абстрактная машина (1.9), оценила бы одно из следующих выражений:

(2.7) - преобразование lvalue-to-rvalue (4.1), если оно не применяется к

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

(2.7.2) - нелетучее значение glvalue, которое относится к подобъекту строкового литерала (2.13.5) или

(2.7.3) - нелетучее значение glvalue, которое относится к энергонезависимому объекту, определенному с помощью constexpr, или к которому относится к не изменяемому под-объекту такого объекта, или

(2.7.4) - нелетучий glvalue буквального типа, который относится к энергонезависимому объекту, срок службы которого начался в рамках оценки e;

Является a || 1 a выражением константы ядра?

4b9b3361

Ответ 1

a не является постоянным выражением (см. стандартную цитату ниже), и поэтому:

a || 1 

Не является также и постоянным выражением, хотя мы знаем, что выражение должно оцениваться как истинное. Этот стандарт требует оценки слева направо, и я не вижу никаких исключений, которые позволяли компилятору пропустить преобразование lvalue-to-rval a.

а

const int a = 1;

Может использоваться в постоянном выражении, потому что он попадает в исключение из 5.20p2 (выделение мое):

преобразование lvalue-to-rvalue (4.1), если оно не применяется к

  • нелетучий glvalue интегрального или перечисляемого типа, который ссылается на полную нелетучую константу объект с предшествующей инициализацией, инициализированный константным выражением или
  • нестабильное значение glvalue, которое ссылается на подобъект строкового литерала (2.13.5) или
  • нестабильное значение glvalue, которое относится к энергонезависимому объекту, определенному с помощью constexpr, или к которому относится к не изменяемому под-объекту такого объекта или
  • нелетучий glvalue буквального типа, который относится к энергонезависимому объекту, срок службы которого начался в рамках оценки e

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

Возможно, gcc позволяет это:

int b[a || 1]{};

как массив переменной длины как расширение, хотя он должен предоставить предупреждение с помощью -pedantic. Хотя это не объясняло бы случай static_assert, они могли бы постоянно складывать его, но я не думаю, что правило as-if позволит ему считаться постоянным выражением. С >

Обновление, возможное расширение gcc

Из этого отчета об ошибке RHS логических операторов может отображать LHS в неизменном выражении, это выглядит как возможное расширение gcc:

Это компилируется без инцидентов, несмотря на использование непостоянного объекта в константное выражение:

int i;
static_assert( i || true, "" );
static_assert( ! ( i && false ), "" );

Предполагается, что || и && являются коммутативными, но короткое замыкание работает только в одном направлении.

и в заключительном комментарии говорится:

Я думаю, что это целенаправленное языковое расширение, которое может использовать переключатель для отключения. Было бы неплохо, если static_assert всегда были строгими.

Это похоже на несоответствующее расширение, которое должно вызывать предупреждение при использовании флага -pedantic, схожащего в тщетном вопросе в Является ли это совместимым расширением компилятора для обработки non-constexpr стандартные библиотечные функции как constexpr?.

С++ 11/С++ 14 Цитата

Раздел 5.20 - это раздел 5.19 в С++ 14 и С++ 11, соответствующая цитата из проекта стандарта С++ 14:

преобразование lvalue-to-rvalue (4.1), если оно не применяется к

  • нелетучий glvalue интегрального или перечисляемого типа, который ссылается на нелетучий const-объект с предыдущая инициализация, инициализированная константным выражением [Примечание: строковый литерал (2.14.5) соответствует массиву таких объектов. -end note] или

  • нестабильное значение glvalue, которое относится к энергонезависимому объекту, определенному с помощью constexpr, или к которому относится к не изменяемому под-объекту такого объекта, или

  • нелетучий glvalue литерального типа, который относится к энергонезависимому объекту, срок службы которого начался в рамках оценки e;

а для проекта стандарта С++ 11:

преобразование lvalue-to-rvalue (4.1), если оно не применяется к

  • glvalue интегрального или перечисляемого типа, который ссылается на нелетучий объект const с предшествующим инициализация, инициализированная постоянным выражением, или

  • glvalue типа literal, который ссылается на нелетучий объект, определенный с помощью constexpr, или который ссылается к под-объекту такого объекта, или

  • glvalue типа literal, который ссылается на энергонезависимый временный объект, чье время жизни не завершено, инициализировано постоянным выражением;

Ответ 2

Повторяя свою цитату:

(2.7) - преобразование lvalue-to-rvalue (4.1), если оно не применяется к

(2.7.1) - долговременное значение целочисленного или перечисляемого типа, которое относится к полному энергонезависимому объекту const с предшествующей инициализацией, инициализированной константным выражением или

a включает преобразование lvalue-to-rvalue. Поскольку a не является объектом const, это означает, что a не является основным постоянным выражением; поэтому a || 1 тоже не является.

Однако, если ваш код:

const int a = 1;

тогда a || 1 будет основным выражением константы.

Ответ 3

Если компилятор проверяет всю цепочку цепей, то он может определить, что "a || 1" является постоянным выражением. Однако поскольку a является переменной, если компилятор не проверяет, что a не был назначен, он не знает, что "a || 1" является постоянным выражением.