Агрегированная инициализация членов в C++14

Имея эту структуру:

struct A {
    struct B {
        int a = 21;
        int b;
        int c = 22;
        int d;
        int e = 23;
    };
    B b1  = { 11, 12 };
    B b2  = { 11, 12, 13 };
    int x;
};

И заявляя:

A a = { { 1, 2, 3, 4 }, { 1 }, 5 };

Согласно Clang (3.8.0) и GCC (5.4.0), это значения 8 возможных комбинаций (a.b1.e и a.b2.a - повторяющиеся случаи) относительно того, где взято начальное значение от (или нет):

a.b1.a = 1   // 111
a.b1.b = 2   // 110
a.b1.c = 3   // 101
a.b1.d = 4   // 100
a.b2.b = 0   // 010    // Why not 12 instead of  0? -> Explained in N3605
a.b2.c = 22  // 011    // Why not  0 instead of 22 ?  Why not 13 ?
a.b2.d = 0   // 000
a.b2.e = 23  // 001    // Why not  0 instead of 23 ?

Принимая во внимание пример в N3605 и стандарте C++14 (ISO/IEC 14882:2014), раздел 8.5.1, пункт 7:

Если в списке меньше инициализаторов-предложений, чем элементов в агрегате, то каждый элемент, не инициализированный явно, должен быть инициализирован из своего инициализатора скобок или равных или, если инициализатор скобок или равных не существует, из пустого списка инициализатора (8.5.4).

Я предполагаю, что случай 010 правильный. Тогда почему случаи 011 (a.b2.c) и 001 (a.b2.e) также не равны нулю? Случай 010 равен нулю, поскольку a.b2 "имеет инициализатор", поэтому "инициализатор нестатического элемента данных игнорируется" (снова N3605). Почему инициализаторы членов по умолчанию также не игнорируются?

На самом деле, читая стандартную цитату C++14, для меня было бы больше смысла, что случай 010 будет 12 (это ноль), а случаи 011 и 001 будут нулем (как они есть на самом деле). Так что я не понимаю, почему a.b2 иногда считают "инициализатором", а иногда - нет.

2 ответа

Решение

Вы заявляете a с инициализаторами для всех его членов: b1, b2 а также x, Это означает, что мы строим, как будто

a.b1 = B{ 1, 2, 3, 4 };
a.b2 = B{ 1 };
a.x = 5;

Bопределение говорит, что B{ 1, 2, 3, 4 } средства B{ 1, 2, 3, 4, 23 } и это B{ 1 } средства B{ 1, 0, 22, 0, 23 }, И это именно тот результат, который вы получаете.


Если бы вы написали

A a = { { 1, 2, 3, 4 }, };

затем a.b2 будет инициализирован с использованием значения по умолчанию { 11, 12 }:

a.b1 = B{ 1, 2, 3, 4 };
a.b2 = B{ 11, 12 };
a.x = {};

Это может помочь думать о таких выражениях скобок, таких как { 1 } а также { 11, 12 } в вашем примере как полностью построенный B объекты, задолго до Aконструктор их даже видит.

В этом примере {1, 2, 3, 4} инициализатор для B b1, Компилятор уже имеет инициализатор, так что теперь он не будет смотреть на { 11, 12 } больше.

Другие вопросы по тегам