`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] говорит, что это не постоянное выражение?
Ответы
Ответ 1
В 5.19:
A [...] выражение является константным выражением, если оно не связано с одним из следующих [...]:
Если это явно, преобразование 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 хорошо.