Well, not always. It would work for templates that don't need a fully defined argument at the point of instantiation.
auto_ptr is a particularly tricky case. The class template itself doesn't need the type to be fully defined. HOWEVER, the destructor of auto_ptr deletes the object it points to, and delete is evil: it doesn't require the full definition, but if it's not available, it is undefined behaviour as far as the standard is concerned. (In other words, your program is invalid, but you might not notice it immediately - or ever.)
The trick here is: whether the UB occurs depends on whether the type is fully defined where delete is used. But where is it used? Well, it's used in the auto_ptr destructor, so it's used whereever that is defined. Because auto_ptr is a template, the destructor of any given instantiation is "defined" (instantiated, actually) directly after the first function it is used in. That, in your case, is the destructor of your class. And the destructor of your class might be auto-generated and therefore be auto-defined directly after the class definition (conceptually). Since the definition is not yet available there, it's UB.
To sum up: assuming you have four files: a pair of .hpp and .cpp for the two classes a and b. Note that a contains an auto_ptr to a b. b doesn't reference a in any form, but the full definition wasn't included in order to keep the inclusion dependencies down. Assume that include guards and appropriate system includes are in place.
a.cpp and b.cpp are irrelevant.Code:
The above gives undefined behaviour when the a is destructed. Weird, huh? To correct it, you could do this:
Now the behaviour is well-defined.Code:
that sounds really weird to me. Thanks for that nice explanation!
It is weird. For this reason, Boost.Shared_Ptr was written in such a way that the UB code above would fail to compile.