Я работаю над мелким (симпатичным) принтером для 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
вместо массивов типа С, но я просто экспериментирую. Чтение текущий проект стандарта 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 (который предъявляет более строгие требования к контейнерам).
Это ошибка в 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};