问题
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 when working with templates. Because templates have to be entirely in the header files (not counting the case when I put the code into cpp and enumerate template class A<T>; for each supported T - this is not always feasible, e.g. when T is a lambda).
So is there a way to declare/define interdependent templates 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 doing something to B in RunA(), I think, I will get a "missing definition" error because only forward declaration of B is available by the time RunA() is compiled.
Perhaps there is some trick to organize header files e.g. by splitting each header into class definition and method definition files, and then including them in some fancy way. Or maybe something can be done via a third/fourth class. But I can't imagine how specifically to do this.
C++11/14/17 are ok (specifically, it's MSVC++2017, toolset v141).
回答1:
You can utilize 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 of these headers also need some sort of header guards that I omitted here. Important notice: .impl.hpp headers are considered internal and should never be used by the outside code while .forward.hpp, .decl.hpp and .hpp can be used anywhere.
This approach does introduce circular include dependencies, however this does not lead to problems: code structure produced by inclusion of headers ensures that code parts are included in the following order: forward declarations, class definitions, methods definitions.
回答2:
You can separate the declarations and definitions of classes. Therefore you can separate the declarations and definitions of template classes...
You can separate the declarations and definitions of class methods. Therefore you can separate the declarations and definitions of 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
}
来源:https://stackoverflow.com/questions/45402913/how-to-declare-define-interdependent-templates-in-c