Can standard container templates be instantiated with incomplete types?

Here's my attempt at an interpretation:

The standard simply says you mustn't do this, even though any given concrete implementation may have no problem supporting such a construction. But imagine for example if someone wanted to write a "small vector" optimization by which a vector always contains space for, say, five elements. Immediately you'd be in trouble because you'd have a self-referential type. This would be a problem even if the vector employed some sort of static branching depending on the size of the value type.

Therefore, in order to not preclude implementations from including such constructions, the standard simply says that you must only use complete types. In other words, the fact that most containers only contain references or pointers to the value type is an implementation detail rather than a standard requirement.

Just to clarify this: if you define your own class template, it is perfectly possible to design it in such a way that it explicitly supports incomplete types. An example from the standard is std::unique_ptr, which is perfectly happy with the incomplete type parameter T[] (or even void).


Personally, I feel the wording instantiating in 17.6.4.8/2 is a little ambiguous, but according to this article, the standard's intent seems not to allow recursive data type using standard containers.

On a related note, VC2005 issues an error for class C { std::deque< C > x; };, while it compiles class C { std::vector< C > x; };...
However, in my understanding, this restriction is just for expanding the freedom of the implementation of standard containers. So as Kerrek SB mentioned, there can be containers which allow recursive data structure, and Boost.Container seems to provide this facility.


In general, using an incomplete type as a template parameter to a standard library component is UB. Here's the reference:

If an incomplete type ([basic.types]) is used as a template argument when instantiating a template component or evaluating a concept, unless specifically allowed for that component.

Note that since c++17, explicit permission has been granted to std::vector to allow incomplete types. Here's the reference:

An incomplete type T may be used when instantiating vector if the allocator meets the allocator completeness requirements. T shall be complete before any member of the resulting specialization of vector is referenced.

So in your example, multi_tree_node is well formed, but trie_node is UB.