bsdsylvia
bsdsylvia

Reputation: 93

No matching function call insert for unorded_map containing shared pointer templates

I am trying to implement a toy ECS for a hobby engine, and am following a small tutorial to kick-start it. An extremely bare-bones implementation using the tutorial is the following

#pragma once

#include <assert.h>

#include <list>
#include <string>
#include <memory>
#include <unordered_map>

#include <entity.hpp>

using ComponentType = std::size_t;

const ComponentType MAX_COMPONENTS = 64000;

class Component
{
    public:
        Component() = default;
};


class IComponentArray
{
    public:
        virtual ~IComponentArray() = default;
        virtual void EntityDestroyed(Entity entity) = 0;
};


template <typename T>
class ComponentArray : IComponentArray
{
    private:
        std::size_t size{};

        std::list<T> componentList{};
    
        std::unordered_map<Entity, size_t> entityToIndexMap{};
        std::unordered_map<size_t, Entity> indexToEntityMap{};
    public:
        ComponentArray() = default;

        void insertData(Entity entity, T component) 
        {
            assert(this->entityToIndexMap.find(entity) == this->entityToIndexMap.end()
                && "Component added to same entity twice!");

            size_t newIndex = this->size;

            this->entityToIndexMap[entity] = newIndex;
            this->indexToEntityMap[newIndex] = entity;

            this->componentList[newIndex] = component;

            ++this->size;
        }
        
        void removeData(Entity entity) 
        {
            assert(this->entityToIndexMap.find(entity) != this->entityToIndexMap.end()
                && "Removing non-existant component!");

            size_t removedEntityIndex = this->entityToIndexMap[entity];
            size_t lastElementIndex = this->size - 1;

            Entity lastElementEntity = indexToEntityMap[lastElementIndex];

            entityToIndexMap[lastElementEntity] = removedEntityIndex;
            indexToEntityMap[removedEntityIndex] = lastElementEntity;

            entityToIndexMap.erase(entity);
            indexToEntityMap.erase(lastElementIndex);
        }

        T& getData(Entity entity) 
        {
            assert(this->entityToIndexMap.find(entity) != entityToIndexMap.end()
                && "Retrieved non-existant component!");

            return this->componentList[entityToIndexMap[entity]];
        }

        void destroyEntity(Entity entity) 
        {
            if (entityToIndexMap.find(entity) != entityToIndexMap.end())
                this->removeData(entity);
        }
};


class ComponentManager
{
    private:
        std::unordered_map<std::string, ComponentType> componentTypes{};
        std::unordered_map<std::string, std::shared_ptr<IComponentArray>> componentArrays{};


        ComponentType nextComponentType{};
    public:
        template <typename T>
        void registerComponent()
        {
            std::string typeName = std::string(typeid(T).name());

            assert(this->componentTypes.find(typeName) == this->componentTypes.end()
                && "Registering component type more than once!");


            componentTypes.insert({typeName, nextComponentType});
            componentArrays.insert({typeName, std::make_shared<ComponentArray<T>>()});


            ++this->nextComponentType;
        }
};

However, when compiling the code, I run into issues with the registerComponent method in ComponentManager.

struct Transform3D
{
    Vector3 position;
};


int main() {
    ComponentManager manager;
    manager.registerComponent<Transform3D>();
}

When commenting or removing the registerComponent line in the second code snippet, the compiler generates no issues, however when uncommenting that line, it spits out a wall of errors, with the top of it saying

no matching function for call to ‘std::unordered_map<std::__cxx11::basic_string<char>, std::shared_ptr<IComponentArray> >::insert(<brace-enclosed initializer list>)’
componentArrays.insert({typeName, std::make_shared<ComponentArray<T>>()});

I have attempted to use something like a pointer to IComponentArray, instead of shared pointers, however, the same error still occurs.

Upvotes: 1

Views: 30

Answers (1)

Some programmer dude
Some programmer dude

Reputation: 409422

That's because std::make_shared<ComponentArray<T>>() returns an object of type std::shared_ptr<ComponentArray<T>>, which doesn't match the data-type of the map.

As a simple solution, define a temporary variable of the right type, initialize it using the make_shared call, and use that variable when inserting the entry into the map:

std::shared_ptr<IComponentArray> array = std::make_shared<ComponentArray<T>>();
componentArrays.insert({typeName, array});

Upvotes: 1

Related Questions