Ответ 1
Таким образом, мы имеем здесь общую инициализацию, описанную в разделе 8.5.1
проекта C++, и в нем говорится:
Агрегатом является массив или класс [...]
а также:
Когда агрегат инициализируется списком инициализаторов, как указано в 8.5.4, элементы списка инициализаторов берутся как инициализаторы для членов агрегата, увеличивая индекс или порядок членов. Каждый элемент инициализируется копией из соответствующего параметра initializer-[[...]
Хотя кажется разумным, что побочные эффекты от инициализации каждого члена агрегата должны быть секвенированы до следующего, поскольку каждый элемент в списке инициализаторов является полным выражением. Стандарт на самом деле не гарантирует этого, мы можем видеть это из отчета об ошибках 1343, который гласит:
В текущей редакции не указывается, что инициализация объекта, отличного от класса, является полным выражением, но, по-видимому, должна это делать.
а также отмечает:
Агрегатная инициализация также может включать более одного полного выражения, поэтому ограничение выше на "инициализацию объекта, отличного от класса", неверно.
и мы можем видеть из связанного стд-дискуссионного раздела Ричард Смит говорит:
[intro.execution] p10: "Полное выражение - это выражение, которое не является подвыражением другого выражения. [...] Если языковая конструкция определена для получения неявного вызова функции, использование языковой конструкции считается выражением для целей этого определения ".
Поскольку бит-init-list не является выражением, и в этом случае это не приводит к вызову функции, 5 и si являются отдельными полными выражениями. Затем:
[intro.execution] p14: "Каждое вычисление значения и побочный эффект, связанный с полным выражением, секвенируются перед вычислением каждого значения и побочным эффектом, связанным со следующим полным выражением, которое должно быть оценено".
Таким образом, единственный вопрос заключается в побочном эффекте инициализации si, "связанного с" оценкой полного выражения "5"? Я думаю, что единственное разумное предположение состоит в том, что: если 5 инициализировали член типа класса, вызов конструктора, очевидно, был бы частью полного выражения по определению в [intro.execution] p10, поэтому естественно предположить что то же самое верно для скалярных типов.
Тем не менее, я не думаю, что стандарт действительно прямо говорит об этом.
Таким образом, в настоящее время этот стандарт не указан стандартом и на него нельзя положиться, хотя я был бы удивлен, если бы реализация не рассматривала его так, как вы ожидаете.
Для простого случая вроде этого нечто похожее на это кажется лучшей альтернативой:
constexpr int value = 13 ;
const int foo[2] = {value, value+42};
Изменения в C++ 17
Предложение P0507R0: Основной вопрос 1343: Последовательность инициализации неклассов уточняет точку полного выражения, поднятую здесь, но не отвечает на вопрос о том, включен ли побочный эффект инициализации в оценку полного выражения. Так что это не изменится, что это не указано.
Соответствующие изменения для этого вопроса находятся в [intro.execution]:
Составляющее выражение определяется следующим образом:
(9.1). Составным выражением выражения является это выражение.
(9.2). Составные выражения списка с привязкой-инициализацией или (возможно, заключенного в скобки) списка выражений являются составными выражениями элементов соответствующего списка.
(9.3) . Составные выражения элемента с равным-равным-инициализатором формы = initializer-clause являются составными выражениями условия initializer. [ Пример:
struct A { int x; }; struct B { int y; struct A a; }; B b = { 5, { 1+1 } };
Составляющие выражения инициализатора, используемые для инициализации b, равны 5 и 1 + 1. -End пример]
Полное выражение
(12.1) - неоцененный операнд (п. 8),
(12.2) - постоянное выражение (8.20),
(12.3) - init-declarator (раздел 11) или mem-initializer (15.6.2), включая составляющие выражения инициализатора,
(12.4) - вызов деструктора, сгенерированного в конце срока жизни объекта, отличного от временного объекта (15.2), или
(12.5) - выражение, которое не является подвыражением другого выражения и которое не является частью полноразмерного выражения.
Таким образом, в этом случае как 13
и foo[0] + 42
являются составными выражениями, которые являются частью полного выражения. Это разрыв с анализом здесь, который полагал, что каждый из них будет их собственным полным выражением.
Изменения в C++ 20
Предложение назначенного инициализации: P0329 содержит следующее дополнение, которое, как представляется, делает это четко определенным:
Добавить новый абзац в 11.6.1 [dcl.init.aggr]:
Инициализация элементов агрегата оценивается в порядке элементов. То есть все вычисления значений и побочные эффекты, связанные с данным элементом, секвенируются до тех, которые соответствуют следующему ему порядку.
Мы видим, что это отражено в последнем проекте стандарта.