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

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

Этот код компилируется и дает ожидаемое: «13 55» в Visual Studio и НКУ, Я просто хотел бы знать, что это законно:

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

24

Решение

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

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

а также:

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

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

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

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

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

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

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

Так как braced-init-list не является выражением, и в этом случае оно
не приводит к вызову функции, 5 и s.i являются отдельными
с полными выражениями. Затем:

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

Так что единственный вопрос, это побочный эффект инициализации s.i
«связано» с оценкой полного выражения «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) — Составные выражения списка скобок-init-списка или (возможно, заключенного в скобки) выражения-списка являются
составные выражения элементов соответствующего списка.

(9.3) — Составные выражения инициализатора фигурной скобки или равенства в выражении form = initializer являются
составные выражения инициализатора-предложения.

[ Пример:

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

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

а также [Intro.execution] р12:

Полное выражение

(12.1) — неоцененный операнд (пункт 8),

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

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

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

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

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

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

Назначенное предложение об инициализации: P0329 содержит следующее дополнение, которое, кажется, делает это хорошо определенным:

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

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

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

20

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]