Можно ли создавать шаблоны стандартных контейнеров с неполными типами? - PullRequest
16 голосов
/ 30 ноября 2011

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

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 объекты по значению.Стандарт, кажется, не очень-то говорит о неполных аргументах шаблона, но в C ++ 11 есть один бит §17.6.4.8 [lib.res.on.functions], «требования к другим функциям»:

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

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

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

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

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

Ответы [ 2 ]

11 голосов
/ 30 ноября 2011

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

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

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

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

4 голосов
/ 01 декабря 2011

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

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

...