Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving a Circular Dependency between Template Classes

Tags:

I have two classes, Foo<T> and Bar<T>, derived from Base. Each overrides a method virtual Base* convert(ID) const, where ID is an instance of a type that uniquely identifies a particular instantiation of Foo or Bar (pretend it's an enum). The problem is that Foo::convert() needs to be able to return a Bar instance, and likewise Bar::convert() needs to be able to instantiate Foo. Since they're both templates, this results in a circular dependency between Foo.h and Bar.h. How do I resolve this?

Edit: A forward declaration does not work because the implementation of each method needs the constructor of the other class:

Foo.h:

#include <Base.h>  template<class T> class Bar;  template<class T> class Foo : public Base { ... };  template<class T> Base* Foo<T>::convert(ID id) const {      if (id == BAR_INT)         return new Bar<int>(value); // Error.      ...  } 

Bar.h:

#include <Base.h>  template<class T> class Foo;  template<class T> class Bar : public Base { ... };  template<class T> Base* Bar<T>::convert(ID id) const {      if (id == FOO_FLOAT)         return new Foo<float>(value); // Error.      ...  } 

The error is, naturally, "invalid use of incomplete type".

like image 672
Jon Purdy Avatar asked Jul 28 '10 14:07

Jon Purdy


People also ask

How do you resolve circular dependency issues?

There are a couple of options to get rid of circular dependencies. For a longer chain, A -> B -> C -> D -> A , if one of the references is removed (for instance, the D -> A reference), the cyclic reference pattern is broken, as well. For simpler patterns, such as A -> B -> A , refactoring may be necessary.

How do I get rid of cyclic dependency?

The Mediator Pattern can also help to lift circular dependencies by encapsulating the bidirectional interaction of two or more objects. The downside of your current code is (besides the circular dependency), that whenever class A changes and also data persistence changes, you have to touch and modify class B.

What is circular dependency error and how do you handle it?

A circular dependency is detected whenever two objects reference each other, in such a way that Power BI cannot process the objects. The details of why this happens are outlined in this article: Understanding Circular Dependencies in Tabular and PowerPivot – SQLBI.

What is cyclic dependency in C++?

Circular Dependencies in C++Its goal is to draw the “include” dependencies between classes in a C++ project. In particular, it allows to detect circular dependencies very easily or to check the architecture of a project.


1 Answers

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.

like image 181
KeithB Avatar answered Oct 05 '22 23:10

KeithB