Двойные фигурные скобки необходимы для инициализации списка контейнера std::array

Инициализация списка контейнеров пользовательских типов ведет себя не так, как я ожидал. См. этот фрагмент:

#include <array>

struct A {
    char C;
    int s;
};

int main(int argc, char * argv[]) {
    A x = {'x'}, y = {'y'};

    std::array<int, 2> i = {1, 2}; // Ok

    std::array<A, 2> a = {x, y}; // Ok
    //std::array<A, 2> b =  { {'x',1000}, {'y',2000} }; // Error: too many initializers!!!
    std::array<A, 2> c = { A{'x',1000}, A{'y',1000} };
    std::array<A, 2> d = {{ {'x',1000}, {'y',1000} }}; // Ok!!
    std::array<A, 2> e = {'x', 2000, 'y', 5000}; // Ok!!
} 

Я могу инициализировать i, как если бы это был фундаментальный массив. Я могу сделать то же самое с a, если они являются переменными. Но я не могу инициализировать b без указания типа A, например, в c.

  1. Чтобы инициализировать std::array без явного указания типа A, я должен добавить еще одну пару фигурных скобок. Какова логика необходимости двойных фигурных скобок? Почему его нельзя инициализировать одной парой фигурных скобок вокруг списка, как в b?

  2. Кроме того, на удивление c работает и дает только два объекта! Интуитивно я ожидал бы, что e выдаст ошибку, потому что есть 4 начальных значения максимум для 2 объектов, но вместо этого компилятор правильно заполняет члены A! Почему это происходит?


person Arjonais    schedule 22.11.2020    source источник
comment
Этот ответ решает вопрос, аналогичный 1), но 2) не ответил.   -  person Arjonais    schedule 22.11.2020


Ответы (1)


Фигурные скобки, как бы глубоко они ни были вложены, сопоставляются со структурой инициализируемого объекта, прежде чем рассматривать какую-либо информацию о типе. Поскольку std::array<T,N> должен содержать истинное T[N] (а не быть таковым), структура такова, что внутри array находится один объект, то есть массив. Поэтому для инициализации этого массива берутся две открывающие фигурные скобки, что не работает, если для инициализации одного элемента массива требуется весь вложенный набор или если таких вложенных наборов больше одного.

Когда какое-либо предложение инициализатора является выражением, даже A{…}, эта декомпозиция останавливается, и инициализатор используется для одного подобъекта. Однако, если это выражение не может быть преобразовано в тип соответствующего подобъекта, и этот тип сам является агрегатом, происходит исключение фигурных скобок, и последующие инициализаторы используются для его подобъектов. несмотря на отсутствие брекетов. Когда это относится к самому объекту T[N], array может быть инициализирован только одним слоем фигурных скобок.

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

person Davis Herring    schedule 23.11.2020