Является ли std::vector<T> `пользовательским типом`?
В 17.6.4.2.1/1 и 17.6.4.2.1/2 текущего проекта стандарта введены ограничения на специализации, введенные пользователями в namespace std
,
Поведение программы на C ++ не определено, если она добавляет объявления или определения в пространство имен std или в пространство имен в пространстве имен std, если не указано иное. Программа может добавить специализацию шаблона для любого шаблона стандартной библиотеки в пространство имен std, только если объявление зависит от типа, определенного пользователем, и специализация соответствует требованиям стандартной библиотеки для исходного шаблона и явно не запрещена.
Я не могу найти, где в стандарте определена фраза пользовательского типа.
Я слышал, что один из вариантов - это тип, который не std::is_fundamental
это пользовательский тип, в этом случае std::vector<int>
будет пользовательским типом.
Альтернативным ответом может быть то, что определяемый пользователем тип - это тип, который определяет пользователь. Как пользователи не определяют std::vector<int>
, а также std::vector<int>
не зависит от типа, определенного пользователем, std::vector<int>
не определенный пользователем тип.
Практическая проблема, на которую это влияет: "Можете ли вы ввести специализацию для std::hash
за std::tuple<Ts...>
в namespace std
? Быть способным сделать это несколько удобно - альтернатива состоит в создании другого пространства имен, в котором мы рекурсивно создаем наш хеш для std::tuple
(и, возможно, другие типы в std
которые не имеют hash
поддержки), и если и только если нам не удастся найти хеш в этом пространстве имен, мы будем использовать std
,
Однако, если это законно, то если и когда стандарт добавляет hash
специализация для std::tuple
в namespace std
код, специализирующий его, уже был бы нарушен, создавая причину не добавлять такие специализации в будущем.
Пока я говорю о std::vector<int>
В качестве конкретного примера я пытаюсь спросить, определены ли типы в std
когда - либо определяемый пользователем тип s. Вторичный вопрос, даже если нет, может быть std::tuple<int>
становится пользовательским типом, когда используется пользователем (это становится скользким: что тогда происходит, если что-то внутри std
определяет std::tuple<int>
, а ты частично специализируешься hash
за std::tuple<Ts...>
).
В настоящее время существует открытый дефект по этой проблеме.
4 ответа
Профессор Страуструп совершенно ясно, что любой тип, который не является встроенным, определяется пользователем. См. Второй абзац раздела 9.1 в Принципах и практике программирования с использованием C++.
Он даже специально называет "стандартные типы библиотек" в качестве примера пользовательских типов. Другими словами, пользовательский тип - это любой составной тип.
В статье прямо упоминается, что, похоже, не все с этим согласны, но это, ИМХО, в основном желаемое за действительное, а не то, что на самом деле говорит стандарт (и профессор Страуструп), а только то, что некоторые люди хотят прочитать в нем.
Когда в пункте 17 говорится "пользовательский", это означает "тип, не определенный в стандарте", поэтому std::vector<int>
не определяется пользователем и не является std::string
так что вы не можете специализироваться std::vector<int>
или же std::vector<std::string>
, С другой стороны, struct MyClass
определяется пользователем, потому что это не тип, определенный в стандарте, поэтому вы можете специализироваться std::vector<MyClass>
,
Это не то же самое значение "пользовательского", которое используется в пунктах 1-16, и это различие является запутанным и глупым. Для этого есть отчет о дефектах, с некоторыми записанными обсуждениями, которые в основном говорят: "Да, библиотека использует неправильный термин, но у нас нет лучшего".
Таким образом, ответ на ваш вопрос "это зависит". Если вы говорите с разработчиком компилятора C++ или экспертом по языку ядра, std::vector<int>
это определенно пользовательский тип, но если вы говорите с разработчиком стандартной библиотеки, это не так. Точнее, он не определен пользователем для целей 17,6.4.2.1.
Один из способов взглянуть на это состоит в том, что стандартная библиотека - это "пользовательский код", если говорить о базовом языке. Но стандартная библиотека имеет другое представление о "пользователях" и считает себя частью реализации, и только вещи, которые не являются частью библиотеки, "определяются пользователем".
Редактировать: я предложил изменить разделы библиотеки, чтобы использовать новый термин, "определяемый программой", что означает нечто определенное в вашей программе (в отличие от UDT, определенных в стандарте, таких как std::string
).
Как пользователи не определяют
std::vector<int>
, а такжеstd::vector<int>
не зависит от типа, определенного пользователем,std::vector<int>
не определенный пользователем тип.
Логический контраргумент состоит в том, что пользователи определяют std::vector<int>
, Ты видишь std::vector
является шаблоном класса и поэтому не имеет прямого представления в двоичном коде.
В некотором смысле он получает двоичное представление посредством создания экземпляра типа, поэтому само действие объявления std::vector<int>
объект - это то, что дает "душу" шаблону (простите за формулировку). В программе, где никто не использует std::vector<int>
этот тип данных не существует.
С другой стороны, следуя тому же аргументу, std::vector<T>
это не определенный пользователем тип, это даже не тип, он не существует; только если мы захотим (создать экземпляр типа), он будет определять порядок расположения структуры, но до тех пор мы можем спорить об этом только с точки зрения структуры, дизайна, свойств и так далее.
Заметка
Приведенный выше аргумент (о том, что шаблоны - это не код, а... хорошо шаблоны для кода) может показаться немного поверхностным, но его логика основана на введении Майера в книгу А. Александреску " Современный дизайн C++". Относительная цитата там выглядит так:
В конце концов Андрей обратил свое внимание на разработку основанных на шаблонах реализаций популярных языковых идиом и шаблонов проектирования, особенно шаблонов GoF[*]. Это привело к короткой стычке с сообществом шаблонов, поскольку один из их основных принципов заключается в том, что шаблоны не могут быть представлены в коде. Как только стало ясно, что Андрей автоматизировал генерацию реализаций шаблонов, а не пытался кодировать сами шаблоны, это возражение было снято, и мне было приятно видеть, как Андрей и один из GoF (Джон Влиссидес) сотрудничают по двум столбцам в отчете C++ сосредоточиться на работе Андрея.
В проекте стандарта базовые типы сравниваются с пользовательскими типами в нескольких (ненормативных) местах.
В проекте стандарта также используется термин "определенный пользователем" в других контекстах, относящийся к объектам, созданным программистом или определенным в стандартной библиотеке. Примеры включают определяемый пользователем конструктор, определяемый пользователем оператор и определяемое пользователем преобразование.
Эти факты позволяют нам, при отсутствии других доказательств, предположительно предположить, что целью стандарта является то, что определяемый пользователем тип должен означать составной тип, согласно историческому использованию. Только явное разъяснение в будущем стандартном документе может определенно решить проблему.
Обратите внимание, что историческое использование не ясно для таких типов, как int*
или же struct foo*
или же void(*)(struct foo****)
, Они составные, но должны ли они (или некоторые из них) считаться пользовательскими?