Могу ли я ссылаться на предыдущих членов списка инициализаторов?

Скажем, я хочу сослаться на член initializer_list, который я уже определил. Могу ли я это сделать?

Этот код компилируется и дает ожидаемое: "13 55 " как в Visual Studio, так и в gcc. знайте, что это законно:

const int foo[2] = {13, foo[0] + 42};

person Jonathan Mee    schedule 20.11.2015    source источник
comment
@ShafikYaghmour Хотя этот вопрос также ссылается на initializer_list, он делает это в формате структуры, а не в формате массива. В ответах есть краткие упоминания о массивах, но все они направлены на ответы, связанные со структурой, которые (потенциально) инициализируются совершенно другим методом. На мой взгляд, это не дубликат, и я, конечно, хотел бы увидеть некоторый анализ того, является ли он законным в контексте массива.   -  person Jonathan Mee    schedule 20.11.2015
comment
Я снова открыл, поскольку можно было утверждать, что ответ для массива может не совпадать с тем, что был в другом вопросе. У меня есть ощущение, что любой ответ, который вы получите, будет выглядеть очень похоже.   -  person NathanOliver    schedule 20.11.2015
comment
@NathanOliver Спасибо, я согласен. Но это совершенно отдельный вопрос. Читать страницы о структурах, чтобы найти ответ на массивы, неконструктивно.   -  person Jonathan Mee    schedule 20.11.2015
comment
DR1343 выглядит так, будто этого недостаточно; что необходимо, так это абсолютное утверждение о том, что для агрегатной инициализации инициализатор не должен оцениваться до завершения инициализации предыдущего элемента. Как говорит Шафик, на данный момент не существует никакой формулировки, препятствующей оценке всех элементов списка, а затем применению результатов к совокупности.   -  person M.M    schedule 23.11.2015
comment
@M.M, ну, трудно сказать, как далеко это зайдет, пока не будет решено. В настоящее время у этого даже нет предложенной формулировки.   -  person Shafik Yaghmour    schedule 23.11.2015
comment
Это список инициализации в фигурных скобках, а не initializer_list, не так ли?   -  person Baum mit Augen    schedule 10.07.2018
comment
@BaummitAugen Да, это   -  person NathanOliver    schedule 10.07.2018
comment
@FrançoisAndrieux Я отметил, сможем ли мы объединить их вместе.   -  person NathanOliver    schedule 10.07.2018
comment
@NathanOliver Вау... Я тупой. Спасибо за ссылку.   -  person Jonathan Mee    schedule 10.07.2018
comment
@FrançoisAndrieux Автор соглашается и обновит ответ позже.   -  person Rakete1111    schedule 10.07.2018
comment
@ Rakete1111 Rakete1111 Я согласен, и я пошел дальше и принял ... но, возможно, имеет смысл добавить это к моему первоначальному вопросу: / Я не совсем уверен.   -  person Jonathan Mee    schedule 10.07.2018
comment
@xskxzr Хотя я согласен, что они похожи, это определенно не дубликат, поскольку он не имеет ничего общего с массивами.   -  person Jonathan Mee    schedule 10.07.2018
comment
@cpplearner интересно, я обновил свой ответ. Я пропустил это предложение, хотя изменения С++ 20, которые я добавил в свой ответ, также делают это законным. Хотя сейчас кажется, что они лишние.   -  person Shafik Yaghmour    schedule 15.07.2018
comment
@cpplearner Я неправильно прочитал предложение, запятая оттолкнула меня. Первоначальный анализ также имел смысл для меня, поэтому мое первоначальное прочтение было предвзятым.   -  person Shafik Yaghmour    schedule 16.07.2018


Ответы (1)


Итак, у нас есть агрегатная инициализация, описанная в разделе 8.5.1 проекта стандарта C++, и там говорится:

Агрегат — это массив или класс [...]

и:

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

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

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

а также отмечает:

Агрегатная инициализация также может включать более одного полного выражения, поэтому приведенное выше ограничение на «инициализацию неклассового объекта» неверно.

и мы можем видеть из связанного std -тема для обсуждения Ричард Смит говорит:

[intro.execution]p10: «Полное выражение — это выражение, которое не является подвыражением другого выражения. [...] Если языковая конструкция определена для создания неявного вызова функции, использование языковой конструкции считается выражением для целей настоящего определения».

Поскольку список инициализации в фигурных скобках не является выражением, и в данном случае он не приводит к вызову функции, 5 и s.i являются отдельными полными выражениями. Затем:

[intro.execution]p14: «Каждое вычисление значения и побочный эффект, связанный с полным выражением, упорядочиваются перед каждым вычислением значения и побочным эффектом, связанным со следующим полным выражением, которое необходимо оценить».

Итак, единственный вопрос: является ли побочный эффект инициализации s.i «связанным с» оценкой полного выражения «5»? Я думаю, единственное разумное предположение состоит в том, что это так: если бы 5 инициализировал член типа класса, вызов конструктора, очевидно, был бы частью полного выражения по определению в [intro.execution]p10, поэтому естественно предположить то же верно и для скалярных типов.

Тем не менее, я не думаю, что стандарт действительно где-либо прямо говорит об этом.

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

Для простого случая, подобного этому, что-то подобное кажется лучшей альтернативой:

constexpr int value = 13 ;
const int foo[2] = {value, value+42};

Изменения в С++ 17

Предложение P0507R0: Основная проблема 1343: Последовательность неклассовая инициализация поясняет поднятую точку полного выражения здесь, но не отвечает на вопрос о том, включен ли побочный эффект инициализации в оценку полного выражения. Так что это не меняет того, что это не указано.

Соответствующие изменения для этого вопроса находятся в [intro.execution]:

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

(9.1) — Составляющее выражение выражения есть это выражение.

(9.2) — Составляющие выражения списка-инициалов в фигурных скобках или (возможно, в скобках) списка-выражений являются составляющими выражениями элементов соответствующего списка.

(9.3) — Составляющие выражения инициализатора скобки-или-равно формы = инициализатор-предложения являются составляющими выражениями инициализатора-предложения. [Пример:

struct A { int x; };
struct B { int y; struct A a; };
B b = { 5, { 1+1 } };

Составные выражения инициализатора, используемые для инициализации b, равны 5 и 1+1. — конец примера]

и [intro.execution]p12:

Полное выражение — это

(12.1) — невычисленный операнд (раздел 8),

(12.2) — константное выражение (8.20),

(12.3) — декларатор инициализации (пункт 11) или мем-инициализатор (15.6.2), включая составные выражения инициализатора,

(12.4) — вызов деструктора, сгенерированного в конце жизни объекта, отличного от временного объекта (15.2), или

(12.5) — выражение, которое не является подвыражением другого выражения и не является частью полного выражения.

Таким образом, в данном случае и 13, и foo[0] + 42 являются составными выражениями, которые являются частью полного выражения. Это отход от здесь который постулировал, что каждое из них будет своим собственным полным выражением.

Изменения в С++ 20

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

Добавьте новый абзац в 11.6.1 [dcl.init.aggr]:

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

Мы видим, что это отражено в последнем проекте стандарта.

person Shafik Yaghmour    schedule 20.11.2015
comment
@ Rakete1111 Rakete1111 Это было совсем недавно добавлено IIRC, я обновлю, когда у меня будет возможность снова посмотреть его. - person Shafik Yaghmour; 10.07.2018
comment
О, вы правы, он был добавлен с назначенными списками инициализаторов :) Спасибо. - person Rakete1111; 10.07.2018
comment
13 и foo[0] + 42 принадлежат одному полному выражению. Так почему же побочный эффект одного инициализатора предшествует побочному эффекту другого? - person xskxzr; 16.07.2018
comment
@xskxzr Я считаю, что вы правы, я неправильно понял предложение в свете анализа здесь, но при повторном прочтении , including the constituent expressions of the initializer запятая не является отдельным пунктом. - person Shafik Yaghmour; 16.07.2018
comment
[dcl.init.list]p4 по-прежнему применяется. - person T.C.; 20.07.2018
comment
@Т.С. в этом обсуждении Ричард не кажется, что этого было достаточно, чтобы показать, что инициализация элементов была явно покрыта. Кроме того, почему предложение назначенного инициализатора добавило бы это предложение, если бы оно было. - person Shafik Yaghmour; 20.07.2018
comment
Это буквально те же слова, просто замена полного выражения на initializer-clause. Либо они оба охватывают этот случай, либо оба нет, но независимо от этого P0507 не влияет на последовательность. P0329 объясняет сразу после абзаца, почему он это сделал (чтобы охватить элементы, не инициализированные явно, что здесь не так). - person T.C.; 20.07.2018
comment
@Т.С. Изменение P0329 говорит The initializations of the elements, а затем говорит value computations and side effects associated with a given element of the aggregate, что не совпадает с [dcl.init.list]p4, которое говорит о initializer-clause и эффектах по отношению к ним. - person Shafik Yaghmour; 20.07.2018
comment
Не в этом дело. До P0507 это, возможно, полные выражения, и каждое вычисление значения и побочный эффект, связанный с полным выражением, упорядочиваются перед каждым вычислением значения и побочным эффектом, связанным со следующим полным выражением, подлежащим оценке. После P0507 они не являются полными выражениями, но все равно каждое вычисление значения и побочный эффект, связанные с данным предложением-инициализатором, располагаются перед каждым вычислением значения и побочным эффектом, связанным с любым инициализатором-. предложение, которое следует за ним в списке initializer-list, разделенном запятыми. - person T.C.; 20.07.2018
comment
P0507 не изменил поведение в этом случае. Инициализация либо связана, либо не связана с предложением инициализатора; является ли предложение-инициализатор полным выражением или нет, не влияет на последовательность. - person T.C.; 20.07.2018
comment
@Т.С. Я понимаю, что вы говорите, P0507 на самом деле не разрешил вопрос обсуждается здесь ... потому что, даже если они являются полными выражениями, они не относятся к So the only question is, is the side-effect of initializing s.i "associated with" the evaluation of the full-expression "5"? - person Shafik Yaghmour; 20.07.2018