Resolving a Circular Dependency between Template Classes
What you need to do is seperate the class declarations from the implementation. So something like
template <class T> class Foo : public Base
{
public:
Base* convert(ID) const;
}
template <class T> class Bar : public Base
{
public:
Base* convert(ID) const;
}
template <class T> Base* Foo<T>::convert(ID) const {return new Bar<T>;}
template <class T> Base* Bar<T>::convert(ID) const {return new Foo<T>;}
This way, you have complete class definitions when the functions are defined.
Template circular dependency - seperate classes in different files
However, this solution (Separating the declaration from the implementation) only works when putting both classes into one file.
No, it doesn't only work in one file. You can always construct an identical file by including sub-headers. It just requires you to do something that would be unusual with non-templates (although same technique works with all inline function definitions): You need to include a file after defining the class. Headers are not limited to being at the top of the file despite the name given to them.
So, in one file:
- Declare
StateManager
- Define
State
- Include definition of
StateManager
- Define member functions that depend on definition of
StateManager
Nothing unusual in the other file:
- Include definition of
State
- Define
StateManager
and its member functions.
The end result is that including either header produces the same definitions and declarations in the required order. So, this splitting of files does in no way help with limiting the amount of re-compilation caused by modifying one of the headers.
It may be a matter of taste, but I always include definitions required by inline functions (including members of templates and template functions) after the definition of the class. That way I don't need to worry whether doing so is necessary.
Circular dependency in template classes
If I make the assumption that you wanted OtherType
to contain a reference to EnclosingType<OtherType>
, you can do the following:
// EnclosingType declaration
template <typename T>
class EnclosingType;
// OtherType definition
class OtherType
{
public:
EnclosingType<OtherType> & e_;
OtherType (EnclosingType<OtherType> & e) : e_(e) {}
};
// EnclosingType definition
template <typename T>
class EnclosingType
{
public:
T type_;
};
You can use the EnclosingType
declaration (as opposed to definition) in OtherType
since you are referencing it via a pointer or reference. EnclosingType<OtherType>
's definition needs the definition of OtherType
because it includes it by value.
Template classes circular dependency issue (c++)
You can solve this problem of circular dependency by removing the #include "Listener.h"
from Dispatcher.h and instead adding a forward declaration for class template Listener<>
as shown below:
Dispatcher.h
#pragma once
#include <vector>
//no need to include Listener.h
//forward declaration
template<typename T> class Listener;
template <typename T>
class Dispatcher {
private:
std::vector<Listener<T>*> m_listeners;
public:
Dispatcher() {}
~Dispatcher() {
for (Listener<T>* l : m_listeners) {
delete l;
}
}
void Attach(Listener<T>* listener) {
m_listeners.push_back(listener);
}
void Detach(Listener<T>* listener) {
std::vector<Listener<T>*>::iterator it = std::find(m_listeners.begin(), m_listeners.end(), listener);
if (it != m_listeners.end()) {
m_listeners.erase(it);
}
}
void Notify(T& event) {
for (Listener<T>* l : m_listeners) {
l->OnEvent(event);
}
}
};
Resolving circular dependency between concept and constrained template function
To my surprise,
std::vector<int>
is not consideredPrintable
, even thoughoperator<<
works on it.
It doesn't. Not really anyway. When you say std::cout << x;
works what you really mean is that you can write that expression from wherever and that works - "from wherever" including in the definition of Printable
. And in the definition of Printable
, it... doesn't work. Unqualified lookup doesn't find it and argument-dependent lookup doesn't find it either. The same will likely be true in most other contexts, unless you carefully add a using operator<<;
in the appropriate place(s).
You could attempt to move the declaration of operator<<
forward, so that the concept definition can see it - but that still wouldn't ultimately resolve the issue of any other code actually being able to call that operator. It can't really work unless this operator is declared in namespace std
. And you're not allowed to add it in there.
But if you could, then this would work fine:
namespace std {
template <class T>
concept Printable = requires (ostream os, T const var) { os << var; }
template <Printable T>
ostream& operator<<(ostream&, vector<T> const&) { ... }
}
Or just use {fmt}
Resolve circular C++ template dependency
I want to do this because A has a callback to B, and B has a callback to A. For example, A would call B.do_work(), and eventually B would call A.done_work().
Ideally you'd avoid the interdepencies in the first place, e.g.:
template<class T> struct A {
std::function<void (T)> handler;
void f(T) {}
void work() { handler(T()); }
};
template<class T> struct B {
std::function<void (T)> fn;
void f(T) {}
void work() { handler(T()); }
};
// ..
A<int> a;
B<int> b;
a.handler = std::bind(&B::f, &b);
b.handler = std::bind(&A::f, &a);
Related Topics
Are All Temporaries Rvalues in C++
Understanding Gcc 5's _Glibcxx_Use_Cxx11_Abi or the New Abi
Why Does the "Static" Keyword Have So Many Meanings in C and C++
Convert First Letter in String to Uppercase
C++ Stack Trace from Unhandled Exception
Undefined Reference to Static Variable
Is There Any Reason Not to Make a Member Function Virtual
Convert a Number to a String Literal with Constexpr
Programmatically Selecting File in Explorer
C++ Trying to Get Function Address from a Std::Function
Getting Std::Thread/Mutex to Work Under Win7 with Mingw and G++ 4.7.2
G++ Always Backward-Compatible with "Older" Static Libraries
How to Iterate Through a List of Objects in C++
Can You Mix C++ Compiled with Different Versions of the Same Compiler