Унифицированная инициализация вектора векторов целых чисел

С++ 11

Программа инициализирует vector с именем myVec, int vector s, а затем использует цикл для печати каждого внутреннего элемента vector. Но я получил неожиданные результаты, пытаясь понять, что происходит, когда я использую лишние фигурные скобки. Ниже приведено также это LiveWorkSpace для легкого переключения между компиляторами. g++ 4.8.0 только компилируется до myVec[5]. clang++ 3.2 скомпилирует все:

#include <iostream>
#include <vector>

int main()
{
    std::vector<std::vector<int>> myVec =
    {
        /* myVec[0] */ {1, 2},
        /* myVec[1] */ {},
        /* myVec[2] */ {{}},
        /* myVec[3] */ { {}, {} },
        /* myVec[4] */ { {}, {}, {} },
        /* myVec[5] */ {{{}}}

        /* myVec[6] */  // , { {{}}, {{}} }       // g++ 4.8.0 COMPILER ERROR
        /* myVec[7] */  // , {{{{}}}}             // g++ 4.8.0 COMPILER ERROR
        /* myVec[8] */  // , { {{{}}}, {{{}}} }   // g++ 4.8.0 COMPILER ERROR
    };

    // loop for printing
    for (unsigned int i = 0; i < myVec.size(); ++i)
    {
        std::cout << "myVec[" << i << "]: ";
        for (unsigned int j = 0; j < myVec.at(i).size(); ++j)
        {
            std::cout << myVec.at(i).at(j) << ", ";
        }
        std::cout << std::endl;
    }
    return 0;
}

Фактический вывод g++ 4.8.0:

myVec[0]: 1, 2,
myVec[1]:
myVec[2]: 0,
myVec[3]: 0, 0,
myVec[4]: 0, 0, 0,
myVec[5]: 0,

Анализ:

myVec[0]: {1, 2}:

Полученный ожидаемый результат.

myVec[1]: {}:

Полученный ожидаемый результат.

myVec[2]: {{}}:

Это вектор int 0. Внутренняя скобка инициализирует int до 0.

myVec[3]: { {}, {} }:

Две внутренние фигурные скобки инициализируют int каждый на 0.

myVec[4]: { {}, {}, {} }:

Три внутренних брекета инициализируют int каждый на 0.

myVec[5]: {{{}}}:

Я хотел добавить еще один набор фигурных скобок в myVec[2], чтобы увидеть, как далеко я могу пойти с добавлением фигурных скобок перед получением ошибок компилятора. Я не понимаю, почему это компилируется и почему его элемент печатает как 0.

Например, int j = {} инициализирует j до 0. vector<vector<int>> v = { {{}} } инициализирует самый внутренний {} до int 0, что делает его эквивалентным vector<vector<int>> v = { {0} }. Затем, что такое vector<vector<int>> u = { {{{}}} } и зачем он компилируется?

Гипотетический myVec[6]: { {{}}, {{}} }:

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

Гипотетический myVec[7]: {{{{}}}}:

Я хотел добавить еще один набор фигурных скобок в myVec[5], чтобы увидеть, как далеко я могу пойти с добавлением фигурных скобок перед получением ошибок компилятора. Я не понимаю, почему это нарушает шаблон и не компилируется.

Гипотетический myVec[8]: { {{{}}}, {{{}}} }:

Я хотел расширить myVec[7], чтобы создать вектор с двумя наборами тройных фигурных скобок. Я не понимаю, почему это тоже не компилируется.

Если все до myVec[5] компилируется, почему остальные не выполняются?

Ответ 1

Попробуйте скомпилировать этот код. это должно объяснить вашу проблему:

int i = {};   // initializes i to int()
int j = {{}}; // fails to compile

почему {{{}}} принят в вашем коде, похоже, ошибка gcc (необходимо уточнить), связанная с обработкой ctor:

struct foo {
    foo( std::initializer_list<int> ) {}
};
void f()
{
   foo bar1( {{{}}} ); // compiles fine
   foo bar2 = {{{}}}; // compiles fine
}

Редактировать (спасибо Йоханнесу Шаубу) - удаление копии ctor делает первый вариант не компилируемым:

struct foo {
    foo( std::initializer_list<int> ) {}
    foo( const foo& ) = delete;
};
void f()
{
   foo bar1( {{{}}} ); // fails to compile: use of deleted function ‘foo::foo(const foo&)
   foo bar2 = {{{}}}; // still compiles, neither deleting move ctor, nor assignment operator does not affect that, is copy ctor of std::initializer_list involved?
}

для функции-члена это не удается:

struct foo {
    void moo( std::initializer_list<int> ) {}
};
void f()
{
   foo bar;
   bar.moo( {{{}}} ); // fails to compile
}

Этот код также не работает:

std::initializer_list<int> l = {{{}}}; // fails to compile

Та же самая ситуация ctor против функции-члена для std :: vector:

void f()
{
    std::vector<int> v( {{{}}} ) // compiles fine;
    v.assign( {{{}}} ); // fails to compile
};

gcc версия 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)