0

Following the advice of this question, I have used late template instantiation to decouple two classes, A and B, which both refer to each other:

#include <iostream>
#include <memory>

template <typename T>
class Bbase {
};      

template <typename T> class BImpl;

template <typename T>
class AImpl
{
public:
    typedef boost::shared_ptr<AImpl> Ptr;
    typename BImpl<T>::Ptr foo();
};

template <typename T>
class BImpl
{
public:
    typedef boost::shared_ptr<BImpl> Ptr;
    typename AImpl<T>::Ptr bar();
};


typedef AImpl<void> A;
typedef BImpl<void> B;

int main () {
        A a;
        B b;
        return 0;
}

The above compiles with no errors.

However, if I try to implement B elsewhere and define an alias class, I get the following compilation errors:

#include <iostream>
#include <memory>

template <typename U>
class Bbase {
public:
    typedef std::shared_ptr<Bbase> Ptr;
    typename U::Ptr bar();
};      

template <typename T> class BImpl;

template <typename T>
class AImpl
{
public:
    typedef std::shared_ptr<AImpl> Ptr;
    typename BImpl<T>::Ptr foo();
};

template <typename T>
using BImpl = Bbase< AImpl<T> >;

typedef AImpl<void> A;
typedef BImpl<void> B;

int main () {
        A a;
        B b;
        return 0;
}

Compiler:

$ g++ foo.cpp --std=c++14                                                                                                                                                                        
foo.cpp:22:32: error: conflicting declaration of template ‘template<class T> using BImpl = Bbase<AImpl<T> >’                                                                                                                                                  
 using BImpl = Bbase< AImpl<T> >;
                                ^
foo.cpp:11:29: note: previous declaration ‘template<class T> class BImpl’
 template <typename T> class BImpl;
                             ^
foo.cpp: In instantiation of ‘class AImpl<void>’:
foo.cpp:28:4:   required from here
foo.cpp:18:28: error: invalid use of incomplete type ‘class BImpl<void>’
     typename BImpl<T>::Ptr foo();
                            ^
foo.cpp:11:29: error: declaration of ‘class BImpl<void>’
 template <typename T> class BImpl;
                             ^
foo.cpp: In function ‘int main()’:
foo.cpp:29:4: error: aggregate ‘B b’ has incomplete type and cannot be defined
  B b;
    ^

I understand the compiler error, that I am trying to redefine a template, but I do not comprehend:

  • Why does the first code snippet work? Is it implementation in the first case and (re)definition in the latter?
  • Can I forward-declare B as a template class and later down declare it as an alias class?

What I would ideally like to do is this:

using A = std::vector< B::iterator >;
using B = std::vector< A::iterator >;
Adama
  • 720
  • 2
  • 5
  • 23
  • *"How can I implement this situation with the `B` class implemented elsewhere, like a template?"* Please elaborate on this. I'm not sure what you mean. – cdhowie Aug 31 '17 at 00:30
  • @cdhowie Thank you for your feedback, I elaborated on what I am trying to achieve. Please let me know if more clarifications are needed. :) – Adama Aug 31 '17 at 09:04
  • It's still not clear to me what your actual goal is. A practical example would help. Pseudocode isn't that useful here because I can see multiple ways to simplify it that may not work with the real code. ([For example](http://coliru.stacked-crooked.com/a/8d4e84fefc1bb2f1)) – cdhowie Aug 31 '17 at 14:50

1 Answers1

1

In the second example, you have this, which forward-declares a template class:

template <typename T> class BImpl;

Then you try to do this, which declares a template alias:

template <typename T>
using BImpl = Bbase< AImpl<T> >;

But an alias is not a class -- you can't define a class by using an alias. The compiler tells you this:

foo.cpp:22:32: error: conflicting declaration of template ‘template<class T> using BImpl = Bbase<AImpl<T> >’

Why does the first code snippet work? Is it implementation in the first case and (re)definition in the latter?

The first code snippet works because it's well-formed; quite simply, there's nothing about it that makes it not work. In the second case, you define an alias with the same name as a class, and that's not allowed.

Can I forward-declare B as a template class and later down declare it as an alias class?

No.

cdhowie
  • 158,093
  • 24
  • 286
  • 300