Categories
不学无术

C++ Template: Handle mutual (circular) dependencies

Sometimes we have two classes that need to call each other’s somewhat function, for example

template <typename A>
struct B
{
    A* p_a_ = nullptr;
};
template <typename B>
struct A
{
    B* p_b_ = nullptr;
};

but as you can see A depends on B’s type to initialize and vise versa. If we declare the types as above we’ll not get a chance to create any instance.
There are at least two ways to resolve the issue.

I.Template template

A quick introduction about template template can be found here.
Declare either of {A, B} with template of template which accepts the other’s template argument.

template <template<typename> typename A_t>
struct B
{
    using A = A_t<B>;
    A* p_a_ = nullptr;
};
template <typename B>
struct A
{
    B* p_b_ = nullptr;
};
//and declare like this
using B_t = B<A>;
B_t b_instance;
A<B_t> A_instance;

II.Type traits

The other resolution is create a type trait struct which acts like a bridge that links the type of each other.

template <typename foobar_tratis>
struct foobar_notifier
{
	using inst_t = typename foobar_tratis::foobar_inst_t;
	inst_t* inst_ = nullptr;
	void foobar()
	{
		std::cout << "foobar_notifier" << std::endl;
	}
};
template <typename foobar_tratis>
struct foobar_inst
{
	using notifier_t = typename foobar_tratis::foobar_notifier_t;
	notifier_t* notifier_ = nullptr;
	void foobar()
	{
		std::cout << "foobar_inst" << std::endl;
	}
};
struct foobar_tratis
{
	using foobar_notifier_t = foobar_notifier<md_inst_traits>;
	using foobar_inst_t = foobar_inst<md_inst_traits>;
};
/// and declare like this
foobar_inst<foobar_tratis> inst2;
foobar_notifier<foobar_tratis> notifier2;

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.