How can I solve the following circular dependency?
typedef boost::variant<int, bool, double, std::string, Structure> Value;
typedef std::list<std::pair<std::string, ValueContainer>> Structure;
typedef std::vector<Value> ValueContainer;
I'm attempting to represent objects from a C api database library in a more C++ form. This database allows one to store values or arrays of values, as well as having a representation for Structures, as follows:
typedef struct ApiStructureMember
{
char* name;
struct ApiValueContainer value;
struct ApiStructureMember_T* next;
} ApiStructureMember_T;
Finally, a union is used to represent a value, as follows:
typedef struct ApiValue
{
union
{
int i;
const char* s;
...
struct ApiStructureMember_T* firstStructureMember;
} value;
} ApiValue_T;
To resolve circular dependencies: Then there are three strategies you can use: Look for small pieces of code that can be moved from one project to the other. Look for code that both libraries depend on and move that code into a new shared library. Combine projectA and projectB into one library.
To reduce or eliminate circular dependencies, architects must implement loose component coupling and isolate failures. One approach is to use abstraction to break the dependency chain. To do this, you introduce an abstracted service interface that delivers underlying functionality without direct component coupling.
In software engineering, a circular dependency is a relation between two or more modules which either directly or indirectly depend on each other to function properly. Such modules are also known as mutually recursive.
A cyclic dependency exists when a dependency of a service directly or indirectly depends on the service itself. For example, if UserService depends on EmployeeService , which also depends on UserService . Angular will have to instantiate EmployeeService to create UserService , which depends on UserService , itself.
You can't have types mutually containing each other. Think about it: the compiler would get into an infinite loop generating the data.
There are two general patterns: the first is through data types pointing to each other
struct OddNode; // forward declaration
struct EvenNode
{
OddNode* prev;
OddNode* next;
};
struct OddNode
{
EvenNode* prev;
EvenNode* next;
};
If you leave away the pointers, and implement the Even and Odd nodes with containment by value, then the compiler can never resolve the definitions.
In general: just draw a picture of how you want to lay out the data, with boxes representing data and lines connecting the various parts. Then replace each box with a class, and each line with a pointer to the corresponding class. If you have a circular dependency somewhere, simply forward declare the classes at the top of your code.
The second circular dependency is through the Curiously Recurring Template Parameter (CRTP)
template<typename T>
struct Y
{};
struct X
:
public Y<X>
{};
Your example would be using the CRTP with Structure
as X
and std::list< ..., Structure>
as Y<X>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With