Topic: Template circular dependencies


Author: jamshid@emx.cc.utexas.edu (Jamshid Afshar)
Date: 28 Sep 1993 23:23:40 -0500
Raw View
Redirected to comp.std.c++.

In article <1993Sep28.183229.10386@bnr.ca>, Al Issa <aissa@bnr.ca> wrote:
>template<class Item> class foo {
>    Item x;
>};
>class bar {
>    foo<bar> fb;
>};

This code is impossible to compile because it is infinitely recursive:
bar contains a foo<bar> which contains a bar, etc.  Then question then
becomes (maybe what you intended): is the following allowed?

 template<class T> class foo {
    T* x;
 };
 class bar {
    foo<bar> f;
 };

or the similar

 template<class T> class foo {
    T x;
 };
 class bar {
    foo<bar>* f;
 };

I believe both examples should be legal and BC++ 3.1, cfront 3.0.1,
and gcc 2.4.3 all agree.  Unfortunately, the following variant causes
all three to give an error that `bar' is incomplete:

 template<class T> class foo {
    T x;
 };
 class bar {
    void m(foo<bar>);  // should be legal, but compilers complain
 };

I think giving an error here is silly -- if the compiler knows it
doesn't need to fully expand a class template when a pointer to it is
used (as in the two previous examples), it should know that it doesn't
need to expand the class template when its used as a parameter type.
I was surprised that even `void m(foo<bar>*);' gave an error.

I do not believe compilers should be allowed to immediately expand
class templates when they are used as a type in the parameter list of
a member function, in a friend declaration, or in a typedef.  The
templates can be expanded after parsing the class definition to
determine the layout and before parsing inline member functions which
are parsed after the class definition via the rewriting rule.

Btw, Taumetric's Mike S. Ball writes about a similar example in the
latest (Oct?) _C++ Report_ and also believes the above code should be
legal.

There's still some questions.  What about:

 template<class Container> class Iter {
    Container::IterState state;
 };
 template<class T> class Array {
 public:
    typedef Iter<Array<T> > MyIter;
    typedef int IterState;
    MyIter current;
 };

I would love for this to be legal and I think it makes sense and is
not too difficult to implement.  I'm not to sure how to specify the
rules, though, since it needs to expand the Array<T>::IterState
typedef to determine the layout of Array<T>.  Comments?

I know I'm pushing it, but what about:

 template<class Container> class Iter {
    typedef int DefaultState;
    Container::IterState state;
 };
 template<class T> class Array {
 public:
    typedef Iter<Array<T> > MyIter;
    typedef MyIter::DefaultState IterState;
    MyIter current;
 };

It's obfuscated, and I don't think I've needed a construct like this,
but the code is theoretically implementable.

Jamshid Afshar
jamshid@emx.cc.utexas.edu