expl0it3r
expl0it3r

Reputation: 335

Use Forwardly Declared Template Class in Header C++

I have a sprite class, which has a templatised data member. It holds an object, which has a pointer to this specialised sprite template class.

That object requires a forward declaration of my sprite class, but since sprite is a template class, I need to include the full header. Therefore I get a cyclic dependancy which I am unable to figure out

Sprite.h

#include "myclass.h"
 template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
    SpriteType s;
    myclass<SpriteType>;
    Sprite() {
    }
    auto foo() {
        return s;
    }

private:

};

myclass.h

#include "Sprite.h"

//a sprite of type T, is going to create a myclass<Sprite<T>>, a pointer of the Sprite<T> is held in myclass.

template<typename T>
class myclass
{
public:
    std::shared_ptr<Sprite<T>> ptr;
    myclass() {

    }
private:

};

How could I solve this cyclic dependency?

So in summary:

-Sprite is a template class.

-Sprite holds an object to another class. This other class holds a pointer to my this templated sprite class.

-This gives me a cyclic dependency, since both classes are now templates, and need to have their implementations written in their header files.

Upvotes: 1

Views: 172

Answers (2)

Taekahn
Taekahn

Reputation: 1692

One of the great thing about templates is breaking type dependencies.
You could do something like this. Simplified for readability.

template<typename T>
class myclass
{
public:
    std::shared_ptr<T> ptr;
    myclass() {

    }
private:

};

template<typename SpriteType, typename = std::enable_if_t<std::is_base_of_v<base_class, SpriteType>>>
class Sprite {
public:
    SpriteType s;
    myclass<Sprite<SpriteType>> t;
    Sprite() {
    }
    auto foo() {
        return s;
    }

private:

};

That is one of many options.
Another option is to use an interface. i.e. a pure virtual base class that isn't a template.

Example: I think something like this should do it. Starting to get a hard to follow though.

class base_sprite
{
    public:
    virtual ~base_sprite(){};

    virtual int foo() = 0;
};

template<typename T>
class myclass
{
public:
    std::shared_ptr<base_sprite> ptr;

    myclass() : ptr(std::make_shared<T>())
    {

    };
};

template<typename SpriteType>
class Sprite : public base_sprite{
public:
    myclass<Sprite<SpriteType>> l;
    int foo() override {return 0;};
};

Upvotes: 1

jvd
jvd

Reputation: 774

Simplified decoupling, based on @Taekahns solution.

template<typename T>
class myclass
{
public:
    std::shared_ptr<T> ptr;
    myclass() {

    }
private:

};

template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
    SpriteType s;
    // DO NOT PASS SpriteType here, put the whole Sprite<SpriteType>
    myclass<Sprite<SpriteType>> t;
    Sprite() {
    }
    auto foo() {
        return s;
    }

private:

};

Upvotes: 1

Related Questions