0

Two template classes can use each other as template argument, but if I use anything defined in one class scope, it cannot be compiled.

template<class B> struct A {
    typedef A *pointer;
};
template<class A> struct B {
    //typedef A::pointer APtr;
    //using APtr = A::pointer;
    //APtr pa;
    A::pointer pa;
};

struct AA;
struct BB;
struct AA : public A<BB> {};
struct BB : public B<AA> {};

VS2017 complained:

1>c:\test.cpp(59): warning C4346: 'pointer': dependent name is not a type
1>c:\test.cpp(59): note: prefix with 'typename' to indicate a type
1>c:\test.cpp(60): note: see reference to class template instantiation 'B<A>' being compiled
1>c:\test.cpp(59): error C2061: syntax error: identifier 'pointer'
1>c:\test.cpp(59): error C2238: unexpected token(s) preceding ';'
1>c:\test.cpp(69): warning C4091: '': ignored on left of 'A<BB> *' when no variable is declared

Is it also involved circular dependency? Is there one possible way to fix it?

samm
  • 620
  • 10
  • 22
  • Notice that `template` is unrelated to `template struct B;` even if you use same name. (it is so just confusing). usual way is to use name `T` (if no relevant/better names). – Jarod42 Aug 17 '19 at 16:09

1 Answers1

1

gcc's error message is much more informative:

t.C:8:5: error: need ‘typename’ before ‘A::pointer’ because ‘A’ is a dependent scope
    8 |     A::pointer pa;
      |     ^
      |     typename 

And doing that, makes gcc happy:

template<class B> struct A {
    typedef A *pointer;
};
template<class A> struct B {
    //typedef A::pointer APtr;
    //using APtr = A::pointer;
    //APtr pa;
    typename A::pointer pa;
};

struct AA;
struct BB;
struct AA : public A<BB> {};
struct BB : public B<AA> {};

This is not a template circular reference. The only reference in the first template is to its own template parameter. Just because its template parameter happens to be named B, and there is another template defined with the same name, later, doesn't make the template parameter a reference to the other template.

And as far as the actual classes go, forward declarations, as in this case, make circular references between classes possible.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148