9

I have two classes that depend on each other:

class Foo; //forward declaration

template <typename T>
class Bar {
  public:
    Foo* foo_ptr;
    void DoSomething() {
      foo_ptr->DoSomething();
    }
};

class Foo {
  public:
    Bar<Foo>* bar_ptr;
    void DoSomething() {
      bar_ptr->DoSomething();
    }
};

When I compile it in g++, it was giving error of "Invalid use of incomplete type", but it was compiled nicely in MSVC 10. Is it possible to solve this problem while keeping the declaration and definition in one header file? (no cpp files) If this is not allowed in the standard, so is this one of the MSVC "bug" or "feature"?

tshepang
  • 12,111
  • 21
  • 91
  • 136
leiiv
  • 865
  • 2
  • 8
  • 14
  • Btw compiles fine on linux. After adding semicolons at the end of class declarations, have you tried moving the implementation to cpp file and leaving just declarations in header? Since Foo and Bar reference each other, will calling DoSomething create infinite loop? – stefanB Feb 17 '10 at 01:19
  • I use g++ 4.4.1, and it's giving error: invalid use of incomplete type ‘struct Foo’. Please don't mind the infinite loop, I have mistakenly making them calling the same method, but we can consider class Foo and Bar have other methods. – leiiv Feb 17 '10 at 01:26
  • 2
    G++ is right: `DoSomething` is a non-dependent name, because there is nothing in the qualifier `foo_ptr->` that would make it depend on a template parameter. As such, it has to be looked up at the template definition time (but at that time, `DoSomething` wasn't declared yet). Dependent names are looked up at instantiation time, instead. Since the MSVC++ compiler does not implement this two-phase lookup, it does not detect this error in your program. – Johannes Schaub - litb Feb 18 '10 at 15:04

3 Answers3

9

Yes, just move the method definitions out of the class definition:

class Foo; //forward declaration

template <typename T>
class Bar {
  public:
    Foo* foo_ptr;
    void DoSomething();
};

class Foo {
  public:
    Bar<Foo>* bar_ptr;
    void DoSomething() {
      bar_ptr->DoSomething();
    }
};

// Don't forget to make the function inline or you'll end up
// with multiple definitions
template <typename T>
inline void Bar<T>::DoSomething() {
  foo_ptr->DoSomething();
}
R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
  • 1
    So there is no way of making it works without separating the class implementation from the definition? – leiiv Feb 18 '10 at 01:12
  • 1
    @leiiv - I don't know of any portable way. But just to be clear, the implementation can still go in the header file; no new source file is required. – R Samuel Klatchko Feb 18 '10 at 01:18
0

See this page: What is the best way to deal with co-dependent classes in C++?

It should clear up the problem and provides a couple nice solutions.

Community
  • 1
  • 1
Nathan Osman
  • 71,149
  • 71
  • 256
  • 361
0

It works when you replace Foo* foo_ptr; by the template parameter T so that you get T* foo_ptr;. In this foo_ptr does not necessarily have to be a pointer or be predefined.

template <typename T>
class Bar {
  public:
    T foo;
    void DoSomething() {
      foo.DoSomething();
    }
};

class Foo {
  public:
    Bar<Foo>* bar_ptr;
    void DoSomething() {
      bar_ptr->DoSomething();
    }
};
Keinstein
  • 347
  • 2
  • 11