James Nguyen
James Nguyen

Reputation: 1171

C++: Templated class pointer conversion

I've encountered an error in my a templated class I've made that holds a pointer to children it later creates. The error generated is a bit weird as I've never seen it.

Code:

template <size_t maxObjects, size_t maxDepth, bool canDelete = false, size_t depth = 0>
struct DynamicQT
{
public:
    DynamicQT(const Aabb2& aabb) : aabb(aabb)
    {

    }
    ~DynamicQT()
    {
        clearObjects();
        destroyBranches();
    }
    void insert(Object* object)
    {
        if (hasBranches())
        {
            if (object->getAABB().overlaps(tl->aabb)) tl->insert(object);
            if (object->getAABB().overlaps(tr->aabb)) tr->insert(object);
            if (object->getAABB().overlaps(bl->aabb)) bl->insert(object);
            if (object->getAABB().overlaps(br->aabb)) br->insert(object);
        }
        else objects[(size_t)object] = object;
    }
    void remove(Object* object)
    {
        if (hasBranches())
        {
            if (object->getAABB().overlaps(tl->aabb)) tl->remove(object);
            if (object->getAABB().overlaps(tr->aabb)) tr->remove(object);
            if (object->getAABB().overlaps(bl->aabb)) bl->remove(object);
            if (object->getAABB().overlaps(br->aabb)) br->remove(object);
        }
        else
        {
            auto result = objects.find((size_t)object);
            if (result != objects.end())
                objects.erase((size_t)object);
        }
    }
    void query(const Aabb2& queryRect, std::vector<Object*>& outVec)
    {
        std::map<size_t, Object*> outMap;
        query(queryRect, outMap);
        if (depth == 0)
        {
            for (const auto& item : objects)
                outVec.push_back(item.second);
        }
    }
    void update()
    {
        throw;
    }
public:
    void query(const Aabb2& queryRect, std::map<size_t, Object*>& outMap)
    {
        if (hasBranches())
        {
            if (queryRect.overlaps(tl->aabb)) tl->query(queryRect, outMap);
            if (queryRect.overlaps(tr->aabb)) tr->query(queryRect, outMap);
            if (queryRect.overlaps(bl->aabb)) bl->query(queryRect, outMap);
            if (queryRect.overlaps(br->aabb)) br->query(queryRect, outMap);
        }
        else outMap.insert(objects.begin(), objects.end());
    }
    void clearObjects()
    {
        if (canDelete)
        {
            for (const auto& obj : objects)
                if (obj.second) delete obj.second;
        }
        objects.clear();
    }
    void createBranches()
    {
        if (!hasBranches() && depth < maxDepth)
        {
            Vector2 half = aabb.halfWidths();
            Aabb2 a(aabb.pos, half);
            Aabb2 b(aabb.pos.addX(half.x), half);
            Aabb2 c(aabb.pos.addY(half.y), half);
            Aabb2 d(aabb.center(), half);
            tl = new DynamicQT<maxObjects, maxDepth, canDelete, depth + 1>(a);
            tr = new DynamicQT<maxObjects, maxDepth, canDelete, depth + 1>(b);
            bl = new DynamicQT<maxObjects, maxDepth, canDelete, depth + 1>(c);
            br = new DynamicQT<maxObjects, maxDepth, canDelete, depth + 1>(d);
        }
    }
    void passObjectsToBranches()
    {
        if (hasBranches())
        {
            Object* obj = nullptr;
            for (const auto& item : objects)
            {
                obj = item.second;
                if (obj->getAABB().overlaps(tl->aabb)) tl->insert(obj);
                if (obj->getAABB().overlaps(tr->aabb)) tr->insert(obj);
                if (obj->getAABB().overlaps(bl->aabb)) bl->insert(obj);
                if (obj->getAABB().overlaps(br->aabb)) br->insert(obj);
            }
            clearObjects();
        }
    }
    void getObjectsFromBranches()
    {
        if (hasBranches())
        {
            objects.insert(tl->objects.begin(), tl->objects.end());
            objects.insert(tr->objects.begin(), tr->objects.end());
            objects.insert(bl->objects.begin(), bl->objects.end());
            objects.insert(br->objects.begin(), br->objects.end());
        }
    }
    void destroyBranches()
    {
        if (hasBranches())
        {
            delete tl;
            delete tr;
            delete bl;
            delete br;
        }
    }
    bool hasBranches() const
    {
        return (tl && tr && bl && br);
    }
public:
private:
    Aabb2 aabb;
    DynamicQT* tl = nullptr;
    DynamicQT* tr = nullptr;
    DynamicQT* bl = nullptr;
    DynamicQT* br = nullptr;
    std::map<size_t, Object*> objects;
};

Note: update is yet to be implemented

The exact error is:

error C2440: '=' : cannot convert from 'DynamicQT<10,10,true,1> *' to 'DynamicQT<10,10,true,0> *'

When I searched for the fix, I had to remove the "depth + 1" or just remove the "+ 1" and compiles fine but obviously is not supposed to happen.

Any help is appreciated (And maybe any problems with the code).

Upvotes: 1

Views: 60

Answers (1)

Brian Bi
Brian Bi

Reputation: 119641

The template parameters of DynamicQT are part of the type of the instantiation. Therefore, DynamicQT<10,10,true,0> and DynamicQT<10,10,true,1> are unrelated types and their pointers cannot be implicitly converted to each other. It seems that if depth is 0 then the children should have depth 1 and so on, so you should declare the child pointers to have the appropriate type:

private:
Aabb2 aabb;
typedef DynamicQT<maxObjects, maxDepth, canDelete, depth+1> ChildDynamicQT;
ChildDynamicQT* tl = nullptr;
ChildDynamicQT* tr = nullptr;
ChildDynamicQT* bl = nullptr;
ChildDynamicQT* br = nullptr;

Upvotes: 1

Related Questions