ошибка C3074: массив может быть инициализирован только списком инициализаторов

Я работаю над мелким (симпатичным) принтером для POD, STL и составных типов, таких как массивы. При этом я также возился со списками инициализации и наткнулся на следующее объявление

std::vector<double[3]> arr{ { 10, 11, 12 }, { 20, 21, 22 } };

Кажется, что и VC2013, и G ++ 4.8 не совсем счастливы и выдают непротиворечивое сообщение об ошибке, которое в любом случае не очень полезно для меня

Для VC ++: error C3074: an array can only be initialized with an initialize-list

Для G ++ 4.8: error: array must be initialized with a brace-enclosed initialize

Так что или здесь нельзя использовать списки инициализации, или мой синтаксис совершенно неверный?

Похожий синтаксис следующий синтаксис

std::vector<std::array<int, 3>>  arr{ { 10, 11, 12 }, { 20, 21, 22 } };

Какова возможная проблема с моим списком инициализации?

  • Заметка Я понимаю, что я должен использовать std::array вместо массивов типа С, но я просто экспериментирую.
  • Заметка Если вы не хотите поиграть с этим, вот IDEONE версия
  • Заметка Кроме того, было бы весьма полезно, если бы вы могли вернуть меня обратно к стандарту.

5

Решение

Чтение текущий проект стандарта C ++ 1y.

До таблицы 99:

T
является
EmplaceConstructible
в
Икс
от
арг
для нуля или более аргументов
арг
, означает, что
следующее выражение правильно сформировано:
allocator_traits :: construct (m, p, args)

Таблица 100:

X(il);              |  Equivalent to      | X(il.begin(), il.end());
--------------------+---------------------+--------------------------------
X(i, j);            |                     | Requires:
X a(i, j);          |                     | T shall be EmplaceConstructible
| into X from *i.

Так std::vector<double[3]> v{ {1,2,3}, {4,5,6} }; действует, если double[3] является EmplaceConstructible от {1,2,3} как элемент списка инициализатора, передаваемого std::vector<double[3]>,

Есть также пункт о прямых итераторах, но это не проблема (так как std::initialzier_list итераторы являются прямыми итераторами).

std::vector<T> занимает std::initializer_list<T> параметр.

Так std::initializer_list<double[3]> список кандидатов.

Первый, std::initializer_list<double[3]> x = {{1.0, 2.0, 3.0}}; не может скомпилировать в gcc. Но предположим, что это ошибка в gcc.

Во-вторых, ::new (nullptr) double[3](std::initializer_list<double>{1.0, 2.0, 3.0}); размещение нового, которое EmplaceConstructable сводится к отсутствию подходящего construct переопределить, не компилируется.

Так double[3] не является EmplaceConstruble из std::initalizer_list<double> ни из double[3] и ничего другого (поскольку ошибка возникает из-за того, что я использовал скобки, а не из-за того, что было в скобках, в месте размещения новых), если только распределитель не делает магию, о которой я не знаю, чтобы избежать размещения новых.

Таким образом, ваш код нарушает текущий черновой стандарт, и, вероятно, C ++ 11 и, конечно, C ++ 03 (который предъявляет более строгие требования к контейнерам).

5

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

Это ошибка в gcc и MSVC; Clang компилирует ваш код правильно.

Последние версии gcc на самом деле аварийно завершают работу («ice») компилятора:

внутренняя ошибка компилятора: проверка дерева: ожидаемый класс «type», имеет «исключительный» (error_mark) в useless_type_conversion_p, в tree-ssa.c: 1189

Стандарт достаточно ясен; от [Dcl.init.list]:

5 — объект типа std::initializer_list<E> построен из списка инициализатора, как если бы реализация выделяла массив N элементы типа E, где N это количество элементов в списке инициализатора. Каждый элемент этого массива инициализируется копией с соответствующим элементом списка инициализатора, и std::initializer_list<E> Объект создан для обращения к этому массиву. […]

Адаптируем пример из этого абзаца:

using E = double[3];
using X = std::vector<E>;
E __a[2] = {{10, 11, 12}, {20, 21, 22}};
X x(__a, __a+2);

Это немного обманывает, хотя; более близкий перевод напишет E __a[2] = {E{10, 11, 12}, E{20, 21, 22}};, который не действителен. Но это конечно является можно копировать-инициализировать массив double[3] из списка фигурных скобок: E __a0 = {10, 11, 12};

3

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