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

`x [0] == 1 постоянное выражение в С++ 11, когда x is const int []?

Является ли следующая программа С++ 11 плохо сформированной?

const int x[] = {1,2,3};

static_assert(x[0] == 1, "yay");

int main() {}

gcc и clang, похоже, так думают, но почему не x[0] == 1 постоянное выражение?

x[0] == 1
subscript operator
*(x+0) == 1
array-to-pointer conversion (int* p = x)
*(p+0) == 1
pointer addition
*p == 1
indirection (lvalue y = x[0])
y == 1
lvalue-to-rvalue conversion:

нестабильное значение glvalue (да, x [0] - значение glvalue и энергонезависимое) интеграла (да, он имеет тип const int) или тип перечисления, который ссылается на нелетучий объект const (да, он имеет тип const int) с предшествующей инициализацией (да инициализируется 1), инициализируется константным выражением (да 1 является постоянным выражением)

Кажется истинным, первый элемент массива x удовлетворяет этим условиям.

1 == 1

?

Является ли это ошибкой компилятора, стандартным дефектом или я что-то не хватает?

Какая часть 5.19 [expr.const] говорит, что это не постоянное выражение?

4b9b3361

Ответ 1

В 5.19:

A [...] выражение является константным выражением, если оно не связано с одним из следующих [...]:

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

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

Если это явно, преобразование lvalue-to-rvalue может выполняться только в постоянных выражениях, если:

  • декларация константного интеграла (или перечисления), инициализированная константой: const int x = 3;.
  • объявление с constexpr: constexpr int x[] = {1,2,3};.
  • временный объект, инициализированный константным выражением...

Ваш пример включает преобразование lvalue-в-rvalue, но не имеет ни одного из этих исключений, поэтому x не является постоянным выражением. Если, однако, вы измените его на:

constexpr int x[] = {1,2,3};

static_assert(x[0] == 1, "yay");

int main() {}

Тогда все хорошо.

Ответ 2

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

Подробнее см.:

https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-discussion/Nv5_2dCHm6M

Отчет скопирован ниже:

Текущая формулировка официального лица С++ 11 до N3690 включительно имеет следующее:

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

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

Следующее объявление в глобальной области:

const int x[2] = {42, 43};

определяет массив из 2 объектов const int, список-инициализированный с помощью {42, 43}

В 8.5.1 [dcl.init.aggr]/2:

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

Итак, инициализатор первого элемента элемента 42 и инициализатором второго элемента элемента является 43.

Выражение *x является значением lvalue и константой ядра. Это влечет преобразование от массива к указателю и косвенное - ни из которых дисквалифицируют выражение как основное постоянное выражение. выражение glvalue относится к первому элементу элемента x. *x является нестабильное значение целочисленного типа (const int), которое относится к нестабильный объект const с предшествующей инициализацией и intialized с постоянным выражением 42.

Поэтому преобразование lvalue-rvalue, примененное к glvalue *xдопускается в постоянном выражении, и поэтому следующее хорошо сформированные:

constexpr int y = *x;

Ни gcc, ни clang trunk в настоящее время не принимают это как константу несмотря на то, что он хорошо сформирован в соответствии со стандартом.

Предполагается ли это?

Полная демо-программа:

const int x[2] = {42, 43};
constexpr int y = *x;
int main() {}

Реализации аналогичным образом терпят неудачу с эквивалентным значением lvalue x[0] as хорошо.