How to declare / define interdependent patterns in C ++?

Usually in C ++, when I need interdependencies between classes, I use forward declarations in the header files, and then include both header files in each cpp file.

However, this approach breaks down when working with templates. Since the templates should be completely in the header files (apart from the case when I put the code in cpp and list the template class A<T>; for each T supported, this is not always possible, for example, when T is a lambda).

So, is there a way to declare / define interdependent patterns in C ++?

Code example

 template<typename T> struct B; template<typename T> struct A { void RunA(B<T> *pB) { // need to do something to B here } }; template<typename T> struct B { void RunB(A<T> *pA) { // need to do something to A here } }; 

If I start to do something with B in RunA() , I think I will get a "missing definition" error, because only the RunA() compiles only the forward declaration from B.

Perhaps there is some trick for organizing header files, for example. dividing each header into class definition and method definition files, and then including them in some fancy ways. Or maybe something can be done through the third / fourth grade. But I can’t imagine how to do this specifically.

C ++ 11/14/17 is fine (in particular, this is MSVC ++ 2017, toolset v141).

0
c ++ include c-preprocessor compilation templates
source share
2 answers

You can use fine-grained headers:

 // A.forward.hpp template<typename T> struct A; // A.decl.hpp #include "A.forward.hpp" #include "B.forward.hpp" template<typename T> struct A { void RunA(B<T> *pB); }; // A.impl.hpp #include "A.decl.hpp" #include "B.hpp" template<typename T> void A< T >:: RunA(B<T> *pB) { // need to do something to B here } // A.hpp // this one should be included by code using A #include "A.decl.hpp" #include "A.impl.hpp" // B.forward.hpp template<typename T> struct B; // B.decl.hpp #include "B.forward.hpp" #include "A.forward.hpp" template<typename T> struct B { void RunB(A<T> *pA); }; // B.impl.hpp #include "B.decl.hpp" #include "A.hpp" template<typename T> void B< T >:: RunB(A<T> *pA) { // need to do something to A here } // B.hpp // this one should be included by code using B #include "B.decl.hpp" #include "B.impl.hpp" 

Obviously, all these headers also need some kind of heading defenders, which I missed here. Important note: .impl.hpp headers are considered internal and should never be used by external code, and .forward.hpp , .decl.hpp and .hpp can be used anywhere.

This approach introduces dependencies with cyclic inclusion, but this does not lead to problems: the code structure created by including headers ensures that parts of the code are included in the following order: forward declarations, class definitions, method definitions.

+1
source share

You can separate class declarations and class definitions. Therefore, you can separate declarations and definitions of template classes ...

You can separate declarations and definitions of class methods. Therefore, you can separate the declarations and definitions of the template class methods:

 template<typename T> struct B; // declaration template<typename T> struct A { // definition void RunA(B<T> *pB); // declaration }; template<typename T> struct B { // definition void RunB(A<T> *pA); // declaration }; // definition template<typename T> void A<T>::RunA(B<T> *pB) { // need to do something to B here } // definition template<typename T> void B<T>::RunB(A<T> *pA) { // need to do something to A here } 
0
source share

All Articles