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 >;