two class circular dependency resolved by templates

Greetings to all!

Below I post a short example where two structures are
having some sort of a circular dependency, which is only
working if templating gets used...

1) I wonder why can't I forward declare: struct Deri;?
2) why it even works with a template if it doesn't
without?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
using namespace std;

#define NO_TEMPLATE

#ifdef NO_TEMPLATE
   struct Deri; // error??

   struct Base
   {
      Base(Deri *d): mPtr(d) { if (mPtr) mPtr->output(); }
   private:
      Deri *mPtr;
   };

   struct Deri:
      public Base
   {
      Deri(): Base(this) {}
      void output() const { cout << "txt!" << endl; }
   };
   // why errors??
#else
   template <class DeriType>
   struct Base
   {
      Base(DeriType *d): mPtr(d) { if (mPtr) mPtr->output(); }
   private:
      DeriType *mPtr;
   };

   struct Deri:
      public Base<Deri>
   {
      Deri(): Base<Deri>(this) {}
      void output() const { cout << "txt!" << endl; }
   };
#endif


int main()
{
   Deri d;
   return 0;
}

Of course it would help if you posted the error.

However, the reason is that you're calling mPtr->output(), and in the fwd declaration there's no such method.

With templates things are different since the compiler doesn't do anything until you really need your class (and at that point you have all the info you need about the class).
Last edited on
gcc version 4.5.2:
g++ -std=c++0x -Wall -Wextra ${obj}.cpp -o ${obj}
.cpp: In constructor ‘Base::Base(Deri*)’:
.cpp:11:46: error: invalid use of incomplete type ‘struct Deri’
.cpp:7:11: error: forward declaration of ‘struct Deri’

How should it be written to work similarly w/o templating?
Hi

standard method is via templates. Classes like Base are called Mixin classes.

You can't forward declare the method, so no easy solution w/o templates (reason is that compiler wouldn't know the visibility of the method).
And BTW, the usage is in general a little different than what you appear to be doing here (which doesn't make much sense, but I guess it's just an example). Mixin classes are used to add "common" methods to a set of classes. Typical example is adding a clone method, somehow like this:

1
2
3
4
5
6
7
8
9
template <class T>
class Cloneable
{
 T* clone() const {return new T(); };
};

class A : public Cloneable<A>
{
};


Now A has a proper clone() method.

Maybe you want to consider nested classes instead? Google pimpl idiom.
KarlisRepsons wrote:
How should it be written to work similarly w/o templating?
You need to implement the constructor in the cpp (not header) where you can include the class/struct needed
Headers and Inclues: Why and How
http://www.cplusplus.com/forum/articles/10627/

This is a good read and explains the correct way to do this.

In your case, forward declaring in the header and then implementing in the CPP is the action to take.
coder777 & LB, thanks for idea. This works (separate files are
just for setting the right order of code!):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using namespace std;

#define NO_TEMPLATE

#ifdef NO_TEMPLATE
   struct Deri;

   struct Base
   {
      Base(Deri *d);
   private:
      Deri *mPtr;
   };

   struct Deri:
      public Base
   {
      Deri(): Base(this) {}
      void output() const { cout << "txt!" << endl; }
   };
   
   Base::Base(Deri *d): mPtr(d) { if (mPtr) mPtr->output(); }
#else
   template <class DeriType>
   struct Base
   {
      Base(DeriType *d): mPtr(d) { if (mPtr) mPtr->output(); }
   private:
      DeriType *mPtr;
   };

   struct Deri:
      public Base<Deri>
   {
      Deri(): Base<Deri>(this) {}
      void output() const { cout << "txt!" << endl; }
   };
#endif


int main()
{
   Deri d;
   return 0;
}


So this is somewhat resolved, just I still don't feel sure
about how it works with templates...
Compilers work templates differently. C++ compilers construct the templated class on demand. In your case, it is constructed when the parsing of Deri is done. Since the compiler have parsed Deri (because it is needed to construct the template), the Base constructor can call the output() method just fine because Deri is no longer an incomplete type.

Yes, the correct way is this last form that you show, separating declaration (prototype) from definition.
Topic archived. No new replies allowed.