srg91 Опубликовано 26 апреля, 2018 Поделиться Опубликовано 26 апреля, 2018 Всем привет. Возможно я просто не выспался, поэтому задаю такие глупые вопросы Потихоньку открываю для себя мир C++ и проходя курсы пишу небольшие тесты. И вот на составлении исходных данных для теста я не смог создать многомерный массив, компилятор очень ругается. Никак не возьму в толк почему. Теперь подробнее. Я создаю вектор массивов векторов и компилятор падает, хотя по мне всё выглядит правильно: vector<array<vector<int>, 2>> cases = { {{1, 5, 3, 4, 2}, {2, 4, 3, 5, 1}}, {{1, 2, 3}, {3, 2, 1}}, {{1, 2}, {2, 1}}, {{1}, {1}}, {{}, {}}, }; Чтобы компилятор не падал, пришлось добавить по скобке для каждой строки, но я в упор не понимаю зачем. Вот это компилируется: vector<array<vector<int>, 2>> cases = { {{{1, 5, 3, 4, 2}, {2, 4, 3, 5, 1}}}, {{{1, 2, 3}, {3, 2, 1}}}, {{{1, 2}, {2, 1}}}, {{{1}, {1}}}, {{{}, {}}}, }; Но тогда тут получается 4 измерения, как по мне, а не 3. Потому что если разложить по измерениям я прихожу к своей реализации: // Одномерный вектор vector<int> cases = {1, 2, 3, 4, 5}; // Превращаем его в вектор массивов vector<array<int>> cases = {{1, 2}, {3, 4}}; // Превращаем его в вектор массивов векторов (перестает компилироваться!) vector<array<vector<int>, 2>> cases = {{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}}; И вроде всё верно, три измерения, но падает с ошибкой error: could not convert '{{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}}' from '<brace-enclosed initializer list>' to 'std::vector<std::array<std::vector<int>, 2ul> >' vector<array<vector<int>, 2>> x = {{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}}; Причем по ошибке не могу нагуглить именно свой случай. Кто-нибудь сталкивался с подобным? Есть какое-то логическое объяснение, почему нужно оборачивать дополнительной скобкой? Если непонятно зачем это всё, я гоняю вот такие тестики, чисто для себя: Спойлер for (auto c : cases) { auto v = c[0]; auto e = c[1]; vector<int> r = TestiruemayaFunction(v); if (r != e) { cout << "Failed on "; for (auto i : v) { cout << i << ' '; } cout << ": "; for (auto i : r) { cout << i << ' '; } cout << " != "; for (auto i : e) { cout << i << ' '; } return; } } Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 26 апреля, 2018 Поделиться Опубликовано 26 апреля, 2018 В общем из-за того что ты создаешь контейнер тебе придется все облачать в скобки, а по скобкам: vector<array<vector<int>, 2>> vector{array<vector<int>, 2>{vector<int>, 2{}}} ...........1...................................2.....................3....... array[0] = {{1, 5, 3, 4, 2}, {2, 4, 3, 5, 1}} array[1] = {{1, 2, 3}, {3, 2, 1}} Если по простому, то под каждый контейнер нужны скобочки как в доках. Почему именно так, а не иначе, на это смогут ответить лишь спецификации C++. Ссылка на комментарий Поделиться на другие сайты Поделиться
srg91 Опубликовано 26 апреля, 2018 Автор Поделиться Опубликовано 26 апреля, 2018 41 минуту назад, partoftheworlD сказал: Если по простому, то под каждый контейнер нужны скобочки как в доках. Ну вот, ты нарисовал по 3 блока скобок. А получается нужно 4, иначе не компилируется. Если разбить на переменные то не нужно: vector<int> x = {1,2,3}; vector<int> y = {4,5,6}; array<vector<int>,2> a = {x, y}; vector<array<vector<int>,2>> r = {a}; Но тогда если раскрывать обратно, то оно не компилируется: Спойлер // Начальный вариант с переменными vector<int> x = {1,2,3}; vector<int> y = {4,5,6}; array<vector<int>,2> a = {x, y}; vector<array<vector<int>,2>> r = {a}; // Раскрываем a vector<int> x = {1,2,3}; vector<int> y = {4,5,6}; vector<array<vector<int>,2>> r = {{x, y}}; // Раскрываем x и y (перестает компилироваться) vector<array<vector<int>,2>> r = {{{1, 2, 3}, {4, 5, 6}}}; И вот я не очень понимаю, зачем нужно писать {{{{1, 2, 3}, {4, 5, 6}}}} вместо {{{1, 2, 3}, {4, 5, 6}}} , ведь в этой записи видно 3 измерения и всё выглядит корректно. Ссылка на комментарий Поделиться на другие сайты Поделиться
temtriss Опубликовано 26 апреля, 2018 Поделиться Опубликовано 26 апреля, 2018 (изменено) 4 часа назад, srg91 сказал: vector<array<vector<int>,2>> r = {{x, y}}; Хм... интересненькая задача))) Правда у меня студия уже тут начинает матерится, на отсутсвие экземпляра конструктора, для соответствующего списка аргументов. Правда я особо не использовал vector, а чаще обходился обычными массивами. Сейчас попробую покапаться, может что-то и найду :)) Блин, думал, что разобрался, уже расписал ответ, и уже по нему понял, что нет Приложу скрин того, как это видит студия, дабы еще больше нас запутать https://drive.google.com/open?id=1OnRtK1surpqcFF_hM7OLqZkwQ4SPGkN3 Судя по скрину студия так же видит. {НашКонтенер{Масив{Элемент масива}}} Если ответ найдется, отпишите тут, а то мне тоже интересно Изменено 26 апреля, 2018 пользователем temtriss Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 26 апреля, 2018 Поделиться Опубликовано 26 апреля, 2018 1 час назад, temtriss сказал: Блин, думал, что разобрался, уже расписал ответ, и уже по нему понял, что нет Уже разобрались, дело было в std::array и его агрегатной инициализации, у него внешние фигурные скобки агрегатный синтаксис инициализации, а внутренние - синтаксис инициализатора массива. Ну как разобрались, понятно в чем дело, но не понятно как это работает. Спойлер Цитата std::array<T, N> - это агрегат: у него нет никаких объявленных пользователем конструкторов, даже если вы не принимаете std::initializer_list . Инициализация с использованием фигурных скобок выполняется с использованием агрегатной инициализации , функции C ++, которая была унаследована от C. «Старый стиль» агрегатной инициализации использует: std::array<int, 4> y = { { 1, 2, 3, 4 } }; В этом старом стиле инициализации агрегата можно выполнить дополнительные фигурные скобки, поэтому это эквивалентно: std::array<int, 4> y = { 1, 2, 3, 4 }; Однако эти дополнительные фигурные скобки могут быть отменены только «в объявлении формы T x = { a }; » (C ++ 11 §8.5.1 / 11), то есть когда используется старый стиль = . Это правило, разрешающее выравнивание фигур, не применяется для прямой инициализации списка. В сноске здесь говорится: «Скобки не могут быть исключены при других использованиях инициализации списка». Существует сообщение о дефекте, касающееся этого ограничения: дефект CWG № 1270 . Если предлагаемая резолюция будет принята, для других форм инициализации списка будет разрешено исключение фигурных скобок, и следующее будет хорошо сформировано: std::array<int, 4> y{ 1, 2, 3, 4 }; 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
srg91 Опубликовано 26 апреля, 2018 Автор Поделиться Опубликовано 26 апреля, 2018 Только что, partoftheworlD сказал: Уже разобрались, дело было в std::array и его агрегатной инициализации, внешние фигурные скобки агрегатный синтаксис инициализации, а внутренний - синтаксис инициализатора массива Ну не до конца всё же. Потому что я пока еще не понимаю, почему для случая vector<array<int, 2>> v = {{1, 2}, {3, 4}}; не используется агрегатный синтаксис, а для случая что я приводил выше - используется Ссылка на комментарий Поделиться на другие сайты Поделиться
partoftheworlD Опубликовано 26 апреля, 2018 Поделиться Опубликовано 26 апреля, 2018 2 минуты назад, srg91 сказал: Потому что я пока еще не понимаю Никто не понимает, кроме тех кто писал стандарт мне так кажется (я уже с этим смерился) Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 26 апреля, 2018 Поделиться Опубликовано 26 апреля, 2018 Может так Предполагаю, что там где описание массива из векторов —там кажется что скобки лишние. Двойка в описании массива означает инициализацию двух элементов, которые можно заполнить в массиве после знака "=", что и происходит Ссылка на комментарий Поделиться на другие сайты Поделиться
srg91 Опубликовано 26 апреля, 2018 Автор Поделиться Опубликовано 26 апреля, 2018 1 минуту назад, MasterGH сказал: Предполагаю Ты не очень правильно выделил красным, красное - это вот эти два раздельных вектора: Спойлер А синим действительно это инициализация массива, только почему-то с использованием агрегатного синтаксиса. Осталось понять, почему в случае если массив содержит вектора - используется агрегатный синтаксис. А если содержит числа например, то не агрегатный. 10 минут назад, partoftheworlD сказал: Никто не понимает, кроме тех кто писал стандарт мне так кажется (я уже с этим смерился) Точно, а компилятор на самом деле отправляет сигнал в космос, в котором он пролетая сквозь хаскелевые экзопланеты балуется монадами и находит ответ 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 26 апреля, 2018 Поделиться Опубликовано 26 апреля, 2018 8 часов назад, srg91 сказал: Чтобы компилятор не падал, пришлось добавить по скобке для каждой строки, но я в упор не понимаю зачем. 1 час назад, srg91 сказал: Осталось понять, почему в случае если массив содержит вектора - используется агрегатный синтаксис. А если содержит числа например, то не агрегатный. Как я помню. Вектор — класс, массив — структура. В первом случае будут поинтеры, во втором адреса данных. Может быть разные типы данных связаны с дополнительным блоком скобок. @srg91, если есть возможность, то мог бы в CE DessectData развернутую иерархию данных заскринить. Было бы интересно посмотреть на поинтеры Ссылка на комментарий Поделиться на другие сайты Поделиться
srg91 Опубликовано 26 апреля, 2018 Автор Поделиться Опубликовано 26 апреля, 2018 2 часа назад, MasterGH сказал: если есть возможность Ну, если очень мельком глянуть (я попытался посмотреть структуру вектора в исходниках, но у меня не получилось :)), то выглядит следующий код выглядит примерно так: vector<int> x = { 1,2,3 }; vector<int> y = { 4,5,6 }; array<vector<int>, 2> a = { x, y }; vector<array<vector<int>, 2>> r = { a }; Спойлер где красное - вектора x и y, синее массив a их объединяющий и оранжевый - общий вектор r. Да, массив, судя по исходникам, является классом, но в памяти выглядит как подряд идущие объекты, поэтому вложенные в него вектора идут ровно подряд. Сам вектор похоже состоит из 4-х указателей, 3 из которых я так и не понял что, а вот второй - ссылка на текущий массив данных. 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
X86Jumps Опубликовано 26 апреля, 2018 Поделиться Опубликовано 26 апреля, 2018 проще было бы использовать тогда уже vector а не array а облачать еще в скобки нужно потому что это уже не просто данные массива упрощенно array это template<class Ty, size_t Size> struct {Ty[Size] data;} а подобные простые классы или структуры (или union) можно инициализировать упрощенно у меня уже тут ошибку дает std::vector<std::array<int, 2>> data2 = { { 1, 2 } }; а вот так не дает std::vector<std::vector<int>> data = { { 1, 1 } }; можно присваивать, как ты присвоил a с vector of array не пашет упрощение, потому что список инициализации для вот тут про это говорится https://stackoverflow.com/questions/6041459/c-vector-of-arrays из-за того что это уже не просто array, а vector<array> правило для упрощения инициализации не работает можно еще тут прочесть (не сказать что я все уяснил)) ) http://ru.cppreference.com/w/cpp/container/array http://ru.cppreference.com/w/cpp/container/vector http://ru.cppreference.com/w/cpp/language/aggregate_initialization http://ru.cppreference.com/w/cpp/language/list_initialization (хотя кажется лучше en версию читать)) ) чтобы понять как он хранится в памяти проще в ide дебаг запустить и посомтреть locals (у vector есть allocator,allocator_vals,first,last) 2 2 Ссылка на комментарий Поделиться на другие сайты Поделиться
srg91 Опубликовано 26 апреля, 2018 Автор Поделиться Опубликовано 26 апреля, 2018 15 минут назад, X86Jumps сказал: вот тут про это говорится Спасибо, очень похоже на то. Если я правильно понял из ответа на stackoverflow, то из-за строения array мы должны инициализировать его и одновременно инициализировать его внутренний _Ty _Elems[_Size]; И, получается, по хорошему массивы всегда должны задаваться с двумя скобками. Но при этом есть "специальное правило", которое позволяет "опускать" лишние скобки в случае инициализации агрегатов, но только с условием что это "простая" инициализация, по типу std::vector<std::array<int, 2>>. Если массив содержит что-то, что нужно дополнительно инициализировать, скобки обязательны. Поэтому собственно с array<int, 2> работает, а с array<vector..., 2> нет. Кажется что-то стало более менее понятно, спасибо большое! 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
temtriss Опубликовано 29 апреля, 2018 Поделиться Опубликовано 29 апреля, 2018 В 26.04.2018 в 23:52, X86Jumps сказал: у меня уже тут ошибку дает У меня так же было)) Для устранения #include <array> Да у меня тоже студия видила std::array, но ругалась на какую-то хрень :) Подключил array перестала ошибка вылезать)) Ссылка на комментарий Поделиться на другие сайты Поделиться
X86Jumps Опубликовано 29 апреля, 2018 Поделиться Опубликовано 29 апреля, 2018 2 часа назад, temtriss сказал: У меня так же было)) Для устранения #include <array> ошибка правильно выходила, эта не баг выше я описал причину. Без #include <array> я бы даже не смог использовать этот контейнер из stl (хотя он еще в tr) Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения