It is true that, in general, it is invalid to instantiate templates from the standard library with arguments that are incomplete types:
[res.on.functions]/2 In particular, the effects are undefined in the following cases:
(2.5) — if an incomplete type (6.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.
However, Foo(Foo& f)
is not an incomplete type, even if Foo
is:
[basic.types]/5 A class that has been declared but not defined, an enumeration type in certain contexts (10.2), or an array of unknown bound or of incomplete element type, is an incompletely-defined object type. Incompletely-defined object types and cv void
are incomplete types...
Foo(Foo& f)
is a function type. It's not listed in this definition, so cannot possibly be incomplete.
std::vector
is specifically allowed to be instantiated with an argument that is an incomplete type:
[vector.overview]/3 An incomplete type T
may be used when instantiating vector if the allocator satisfies the allocator completeness requirements (20.5.3.5.1). T
shall be complete before any member of the resulting specialization of vector
is referenced.