Иногда полезно создать стандартный контейнер с неполным типом, чтобы получить рекурсивную структуру:
struct multi_tree_node { // Does work in most implementations
std::vector< multi_tree_node > child;
};
struct trie_node { // Does not work in most implementations
std::map< char, trie_node > next;
};
Обычно это работает, потому что у контейнеров нет элементов типа value_type
или функций-членов, которые передают или возвращают какие-либо объекты value_type
по значению. Стандарт, похоже, не очень много говорит о неполных аргументах шаблона, но есть один бит в С++ 11 §17.6.4.8 [lib.res.on.functions], «требования к другим функциям»:
В частности, эффекты не определены в следующих случаях: … если неполный тип (3.9) используется в качестве аргумента шаблона при создании экземпляра компонента шаблона, если это специально не разрешено для этого компонента.
Делает ли это приведенные выше конструкции незаконными, даже если экземпляры не находятся в области блока? Подпадает ли это под «операции над типами, используемыми для создания экземпляров компонентов шаблона стандартной библиотеки» (также 17.6.4.8)? Или реализации библиотеки запрещено создавать экземпляры шаблонов, которые могут дать сбой для неполных типов, когда все конкретно требуемые экземпляры выполняются успешно?
Редактировать: Поскольку только функции могут вызывать и создавать экземпляры других функций, ограничение «операций над типами…» теми, которые находятся в области блока, казалось бы, предъявляет к содержимому функций-членов более строгие требования, чем к содержимому сигнатур и определения классов-членов. В конце концов, безусловно, нет смысла делать что-либо с multi_tree_node
, пока тип не будет завершен. И это распространяется на std::unique_ptr
, который явно поддерживает аргумент неполного типа, даже при использовании в области блока.
Правка 2: мне очень хорошо, что я не удосужился протестировать пример trie_node
— а я уже пробовал его раньше. Это то же самое, что и пример поломки в статье, на которую ссылается @Ise. Однако, хотя в статье кажется само собой разумеющимся, что «ничего подобного не может работать», решение кажется мне простым — внутренний класс std::map
tree_node
должен быть шаблоном, не являющимся членом, а не классом, не являющимся членом.
В любом случае, эта статья довольно хорошо устанавливает замысел дизайна, поэтому я думаю, что моя придирка к подзаголовку «требования к функциям» - это только это.
trie_node
является неполным при определенииnext
. - person Matthieu M.   schedule 30.11.2011[17.4.3.6]
в стандарте С++ 03, для всех, кто заинтересован. Кроме того, лучше всего также добавить тег, под которым идет абзац, в данном случае[lib.res.on.functions]
. - person Xeo   schedule 30.11.2011