Можно ли создавать стандартные шаблоны контейнеров с неполными типами?

Иногда бывает полезно создать экземпляр стандартного контейнера с неполным типом для получения рекурсивной структуры:

struct multi_tree_node { // Does work in most implementations std::vector child; }; struct trie_node { // Does not work in most implementations std::map next; }; 

Это работает, потому что в контейнерах нет элементов типа value_type или функций-членов, которые передают или возвращают объекты value_type по значению. Стандарт, похоже, не очень много говорит о неполных аргументах шаблона, но есть один бит в C ++ 11 §17.6.4.8 [lib.res.on.functions], «требования к другим функциям»:

В частности, эффекты не определены в следующих случаях: … если неполный тип (3.9) используется в качестве аргумента шаблона при создании экземпляра компонента шаблона, если это специально не разрешено для этого компонента.

Означает ли это, что приведенные выше конструкции незаконны, даже если экземпляры не находятся в блочной области? Подходит ли это к «операциям над типами, используемыми для создания стандартных компонентов шаблона библиотеки» (также 17.6.4.8)? Или реализация библиотеки запрещена для создания экземпляров шаблонов, которые могут завершиться неудачно для неполных типов, когда все требуемые экземпляры будут успешными?

Изменить: поскольку только функции могут вызывать и создавать экземпляры других функций, ограничение «операций с типами …» с теми, которые находятся в области блока, похоже, будет содержать содержимое функций-членов более строгому требованию, чем содержание подписей и определений classов членов. В конце концов, конечно, не имеет смысла ничего делать с помощью multi_tree_node пока тип не будет завершен. И это распространяется на std::unique_ptr который явно поддерживает аргумент неполного типа, даже если он используется в области блока .

Редактировать 2: Служит мне правильно, чтобы не потрудиться протестировать пример trie_node – и я даже пробовал это раньше. Это то же самое, что и пример разрыва в статье , связанный с @Ise. Тем не менее, хотя статья кажется само собой разумеющейся, что «ничего подобного не может работать», решение кажется мне простым std::map tree_node class tree_node std::map должен быть tree_node -членом, а не членом classа без шаблона ,

Во всяком случае, эта статья очень хорошо устанавливает намерение дизайна, поэтому я думаю, что моя проблема в том, что она находится под подзаголовком «требований к функциям», это только так.

Лично я считаю, что формулировка, созданная в 17.6.4.8/2, немного неоднозначна, но, согласно этой статье , намерение стандарта, похоже, не допускает рекурсивного типа данных с использованием стандартных контейнеров.

В соответствующей заметке VC2005 выдает ошибку для class C { std::deque< C > x; }; class C { std::deque< C > x; }; , тогда как он компилирует class C { std::vector< C > x; }; class C { std::vector< C > x; };
Однако, по моему мнению, это ограничение распространяется только на расширение свободы реализации стандартных контейнеров. Как упоминал Kerrek SB , могут быть контейнеры, которые позволяют рекурсивную структуру данных, и Boost.Container, похоже, предоставляет эту возможность.

Вот моя попытка интерпретации:

В стандарте просто говорится, что вы не должны этого делать, хотя любая конкретная реализация может не иметь проблем с поддержкой такой конструкции. Но представьте, например, если кто-то хотел написать оптимизацию «малого вектора», в которой вектор всегда содержит пространство, например, для пяти элементов. Сразу же у вас будут проблемы, потому что у вас будет самореферентный тип. Это было бы проблемой, даже если бы вектор использовал какое-то статическое ветвление в зависимости от размера типа значения.

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

Просто прояснить это: если вы определяете свой собственный шаблон classа, вполне возможно его спроектировать таким образом, чтобы он явно поддерживал неполные типы. Примером стандартного является std::unique_ptr , который совершенно доволен неполным параметром типа T[] (или даже void ).

  • Расширение шаблона шаблонов Variadic
  • Почему шаблон функции не может быть частично специализированным?
  • Нестандартные параметры шаблона
  • Почему шаблонный вывод не работает здесь?
  • Специализация шаблонов псевдонимов
  • Общая библиотека C ++ с шаблонами: ошибка неопределенных символов
  • Специализированная специализированная специализация classа, в которой шаблонный шаблон является шаблоном
  • C ++ Статическая инициализация члена (внутри шаблона)
  • Как получить список текущих переменных из шаблона Jinja 2?
  • Ограничения шаблона C ++
  • Синглтоны: хороший дизайн или костыль?
  • Давайте будем гением компьютера.