TITLE: instantiating template functions too early

(Newsgroups: comp.lang.c++.moderated, 12 May 98)


BRITTEN: Ian Britten
[snip]

> ... class A has no (relevant) inline methods.  All the
> constructors, assignment operator, destructor, etc are in the .cpp file.
> 
> Thus, having:
>         // In file A.h
>         class A {
>         public:
>               A(void);
>               ~A(void);
>         private:
>               A(const A &)
>               A& operator=(const A &);
>               auto_ptr<B> member;
>         };
> 
>         // In file A.cpp
>         #include "A.h"
>         #include "B.h"
> 
>         A::A(void)
>         {
>                 this->member = new B();
>         }
> 
>         A::~A(void)
>         {
>                 // B is deleted here, and only here
>         }
> 
> In this case, am I allowed to use just a forward declaration of class B in
> A.h?  Anyone that has worked on large-scale projects knows the
> ramifications and drawbacks from needlessly #including B.h in A.h, and I'm
> hoping the compiler writers know this too!  Thus, I'm _hoping_ that most
> of the compilers are correct and that MS is wrong, but I'm seeking
> clarification before changing our code.
> 
> I'd also appreciate (if possible) an authoritative reference supporting
> yes or no answers.  I have my opinion of how it should work (as I'm sure
> you do!), but I'm looking for facts.
> 
> [ Hmm... I just had a thought.  Is this something that is specified by the
> standard, or is it one of those things left up to the compiler
> implementors? ]
> 
> Again, any information is appreciated...


ELTSCHKA: Christopher Eltschka <celtschk@physik.tu-muenchen.de>

If you don't change the auto_ptr outside your implementation
file (and all member functions which the compiler might generate
are explicitly given, so the compiler doesn't generate them),
on a standard conforming compiler you should IMHO be safe.

However, there are compilers which instantiate template member
functions too early, namely where the template class is
instantiated. For those compilers, the member functions
of auto_ptr<B> are already instantiated when the member is
declared, and therefore the resulting code is wrong.

You can easily test if your compiler gets this wrong with the
following piece of code:

template<class T> struct X
{
  void f() { g(T()); }
};

class Y {};

X<Y> x;

int main()
{
}

If your compiler complains about g not defined, it instantiates
the template function too early (indeed, in this code it shouldn't
be instantiated at all). Otherwise, if this code compiles fine,
your code should be fine as well (if all the other conditions
above hold, of course).

If you want to be on the safe side, you could make an include file
containing basically the code above, which is only included with
#ifndef TOO_EARLY_TEMPLATE_MEMBER_INSTANTIATION, and then on
the #else part #include "B.h". This way, on conforming compilers,
you'll get no compile time dependency, and on non-conforming (in
this respect) you are guaranteed to get an error if you forget the
define, and get working code otherwise (although with more
coupling).
