Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CRTP with a Cyclic Dependency

Tags:

c++

c++11

crtp

I have a hierarchy of operations and (shared) information classes where intuitively it seems like there is no need for runtime polymorphism, and yet I can't find a solution without it.

For the sake of this question, suppose there is a 2-level hierarchy. There is a base operation and a derived operation. Objects from the same level of the hierarchy might need to share information between them (meaning that base-operation objects need to share base information, and derived operation objects need to share derived information, but base operation objects never need to share derived information or vice versa).

So it starts off like this:

// Shared between base operation objects
class base_info
{

};

// Shared between derived operation objects
class derived_info :
    public base_info
{

};

Given that there is no runtime-question about which operation objects share which information objects, there is also the following:

template<class Info>
class base_op
{
    std::shared_ptr<Info> m_info; 
};

class derived_op :
    public base_op<derived_info>
{

};

The rest of the code always instantiates base_op with base_information, and so no runtime polymporphism is needed up to here.

Now, at some points, the shared information objects can decide they need to spawn new operations. As seen above, operation objects need shared pointers to shared information objects. So the information hierarchy changes to this:

// Shared between base operation objects
class base_info :
   private std::enable_shared_from_this<base_info>
{
    void do_something_spawning_new_ops();
};

...

The problem now is how to implement do_something_spawning_new_ops. With runtime polymporphism, it's not that difficult:

class base_info :
   private std::enable_shared_from_this<base_info>
{
    void do_something_spawning_new_ops()
    {
        // Need a new op.
        get_op_shared_ptr();
    }

    virtual std::shared_ptr<base_op> get_op_shared_ptr()
    {
        // use shared_from_this, create a base_op object using it.
    }
};

class derived_info :
    public base_info
{
    virtual std::shared_ptr<base_op> get_op_shared_ptr()
    {
        // use shared_from_this + std::*_pointer_cast, 
        //    create a derived_op object
    }    
};

but the point is to avoid runtime polymorphism, since by design, everything can be known at instantiation. So going back to the beginning of the post, it would have been nice to have something like this:

template<class Op>
class base_info
{

};

class derived_info :
    public base_info<derived_op>
{

};

with a CRTP sort of thingy (albeit without the derivation) where the op says that it holds an info creating objects of this type. But this now causes a cyclic problem for the instantiation of base_op. It somehow needs to be instantiated by some information type that is itself instantiated by its own type, etc. etc. I do not know how to brake this type-cycle.

Edit

Following Panta rhei's suggestion, here is the code I'm aiming for.

like image 765
Ami Tavory Avatar asked May 09 '15 13:05

Ami Tavory


1 Answers

I'm still not quite sure what you are trying to achieve but all you need to do to make your code compile is to add a type argument in the base_info class template when you instantiate it in main.

int main()
{
    derived_op d;
    base_op<base_info<derived_info> > b;
}
like image 110
Constantinos Glynos Avatar answered Sep 21 '22 01:09

Constantinos Glynos