C++ вектор массивов

Почему это работает:

std::pair<int, int> p = {1,2};
std::vector<std::pair<int, int>> vp = { {1,2}, {3,4} };

Но это не так?

std::array<int, 2> a = {1,2}; // still ok
std::vector<std::array<int, 2>> va = { {1,2}, {3,4} };

При использовании g++ 4.5.1 с -std=c++0x вторая строка завершается с ошибкой:

ошибка: не удалось преобразовать ‘{{1, 2}, {3, 4}}’ в ‘std::vector<std::array<int, 2u> >’

Спасибо


person andreabedini    schedule 18.05.2011    source источник
comment
можете уточнить не получается? (например, указать ошибку вашего компилятора?)   -  person Mat    schedule 18.05.2011
comment
Какая ОС? Может быть ошибка компилятора   -  person BЈовић    schedule 18.05.2011
comment
@VJo @mat добавлено больше деталей, спасибо!   -  person andreabedini    schedule 18.05.2011
comment
На самом деле я подозреваю, что gcc 4.5.1 не полностью соответствует этому вопросу. К сожалению, я не знаю онлайн-компилятора, который мог бы здесь помочь (ideone использует 4.5.1).   -  person Matthieu M.    schedule 18.05.2011


Ответы (2)


К сожалению, std::array не имеет конструктора списка инициализаторов. Действительно, у него нет определяемого пользователем конструктора — эта «функция» является пережитком C++03, где исключение всех определяемых пользователем конструкторов было единственным способом включить инициализацию фигурных скобок в стиле C. . ИМХО это недостаток текущего стандарта.

Так почему же в этом случае не работает встроенная инициализация фигурной скобки? Посмотрим, как std::array выглядит под капотом:

template <typename T, int i> struct array {
    T data[i];
    // ...
}

Хорошо, значит ли это, что нам придется использовать двойные фигурные скобки в инициализаторе (одна пара для array, другая пара для члена data?

std::array<int, 2> a = { {1, 2} };

C (и, следовательно, C++) имеет специальное правило относительно удаления фигурных скобок, разрешающее опускать внутренние фигурные скобки, если нет двусмысленности. array использует эту функцию, позволяя нам писать

std::array<int, 2> a = { 1, 2 };

Так почему же не работает пример в исходном посте? Поскольку исключение фигурных скобок разрешено только в контексте агрегатной инициализации в стиле C, а не в том случае, если задействовано что-то более сложное, например пользовательский конструктор списка инициализаторов.

Следующее должно работать, как бы ужасно оно ни было:

std::vector<std::array<int, 2>> vp = { {{1,2}}, {{3,4}} };

Тот факт, что это не так, по крайней мере, на gcc 4.5 и gcc 4.6, мне кажется, указывает на ошибку компилятора. Хотя я не совсем в этом уверен.

Этот вопрос несколько актуален: Как мне инициализировать массив элементов с initializer_list?

person JohannesD    schedule 18.05.2011
comment
Я скорее подозреваю, что std::array больше похоже на template <typename T, std::size_t i> - person Chris Lutz; 18.05.2011
comment
Да, ваш последний пример должен работать. Это было сознательное и обсуждаемое решение не поддерживать исключение фигурных скобок для чего-либо, кроме простого объявления T t = { ... }. Вот почему return { ... } не будет работать с типом возврата std::array<>. - person Johannes Schaub - litb; 18.05.2011
comment
Ваш последний пример std::vector‹std::array‹int, 2›› vp = {{{1,2}}, {{3,4}} }; работает на gcc 4.7.2 - person Ricky65; 02.04.2013

Это работает:

std::vector<std::array<int, 2>> va = {
  std::array<int, 2>{1,2},
  std::array<int, 2>{3,4}
};

Копнув глубже, кажется, что у std::pair есть конструктор, который принимает список инициализаторов, а у std::array нет:

std::pair<int, int> p ({1,2}) ;  // OK
std::array<int, 2> a ({1,2}) ;   // Invalid

Но теперь я не в своей тарелке.

person TonyK    schedule 18.05.2011
comment
вы фактически сделали это для компилятора, чтобы вывести типы элементов в списке инициализаторов фигурных скобок. Я предполагаю, что проблема именно в этом, но до сих пор не знаю, должно ли это работать по стандарту или нет. - person Matthieu M.; 18.05.2011