2015-10-16 2 views
8

Этой программа плохо образованно:Использования временного массива в качестве именующего

struct X { int i; }; 

int main() { 
    (X { }).i = 1; 
} 

i, субобъект временного X { }, не может быть использован в качестве именующего, потому что X { } является Rvalue.

Однако, это молча компилирует с GCC 5.2.1 и -Wall:

using Y = int[10]; 

int main() { 
    (Y { })[0] = 1; 
} 

Если компилятор правильно, то это время, нулевой элемент (Y { }), который является подобъектом (Y { }), можно лечить как lvalue.

Мои вопросы:

  1. ли плохо формируется вторая программа?
  2. Почему (нет), хотя обе программы, похоже, рассматривают подобъект временного значения как lvalue?
+0

Ошибка Clang была [разрешена в 4.0] (https://bugs.llvm.org/show_bug.cgi?id=25357) –

ответ

8

Я считаю, что второй случай плохо сформированным, если я правильно читал defect report 1213, он говорит:

Поскольку операция индексирования определяются как косвенность через значение указателя, результат индексный оператор, применяемый к массиву xvalue , является значением lvalue, а не значением x. Это может быть удивительно для некоторых.

и разрешение было следующие изменения к проекту C++ стандартный раздел 5.2.1 [expr.sub], (добавлено полужирный срезы и strikethroughs были удалены):

постфиксным выражением а затем выражение в квадратных скобках - это постфиксное выражение . Одно из выражений должно иметь тип «массив Т» или «указатель на Т», а другой должен иметь неперечисленное перечисление или интегральный тип. В результате получается lvalue типа «T.» Тип «T» должен быть полностью определенным типом объекта.62 Выражение E1 [E2] идентично (по определению) на * ((E1) + (E2)) [Примечание: см. 5.3 [expr.unary] и 5.7 [expr.add] для деталей * и + и 8.3.4 [dcl.array] для получения подробной информации о массивах.-end note] , за исключением того, что в случае операнда массива результат равен lvalue, если этот операнд является значением lvalue и xvalue в противном случае.

Результат Y{} является prvalue из секции 5.2.3[expr.type.conv]:

Аналогично, простой тип спецификатор или Ьурепате-спецификатор с последующим приготовился -init-list создает временный объект указанного типа с прямым списком-инициализацией (8.5.4) с указанным скобковым списком инициализации, , а его значение равно , что временный объект как prvalue.

Таким образом, результат (Y { })[0] должен быть xvalue и поэтому плохо формируются с присваиванием требует изменяемого именующего выражения на левом операнде:

Оператор присваивания (=) и операторы присваивания все группа справа налево. Все они требуют изменяемого именующего выражения как их левого операнд [...]

Мы можем найти обновленную формулировку из отчета о дефекте в draft C++14 standard, так что это изменение было применено после C++ 11, но может применяться к C++ 11, поскольку это было применено через отчет о дефектах.

Почему раздел 5.3.1[expr.unary.op] не был также обновлен неясен мне кажется непоследовательным сказать, результат является именующего который не во всех случаях.

Update

Подал clang bug report.

+0

Можете ли вы объяснить, почему значения x не изменяются в этом сценарии? –

+0

@ M.M да, обновлено –

3

Проект стандарта C++ (N4527) § 5.2.1 пункт 1 гласит:

Выражение E1 [E2] идентично (по определению) до * ((E1) + (E2))

§ 5.3.1 пункт 1 гласит:

унарный * оператор выполняет косвенность: выражение, к которому он применяется должен быть указателем на тип объекта, или указатель на веселом ction type и результатом является lvalue, ссылающийся на объект или функцию, на которые указывает выражение.

+0

Кажется, это несоответствие на этом языке. –

Смежные вопросы