2016-11-08 4 views
0

Я перерабатываю Entity Manager системы компонентов Entity. Поскольку компоненты не имеют перекрывающихся функциональных возможностей, я не хочу, чтобы у них была общая база, которую я мог хранить.Следите за экземплярами шаблонов C++

Так я придумал что-то вроде этого:

#include <vector> 
#include <memory> 
#include <iostream> 

class Component1{}; 
class Component2{}; 
class Component3{}; 

class Manager{ 
public: 
    template<typename T> static std::vector<std::shared_ptr<T>> component; 

    template<typename T> static std::shared_ptr<T> getComponent(int nth){ 
    return component<T>[nth]; 
    } 

    template<typename T> static std::shared_ptr<T> addComponent(int nth){ 
    return component<T>[nth] = shared_ptr<T>(new T()); 
    } 

    static void addEntity(){ 
    // push back a nullptr for every instantiated component<> 
    } 

    static void removeEntity(int nth){ 
    // set the nth index of every component<> to nullptr 
    } 
}; 

template<typename T> 
std::vector<std::shared_ptr<T>> Manager::component = std::vector<std::shared_ptr<T>>(); 

int main(){ 
    Manager::component<Component1>; 
    Manager::component<Component2>; 
    Manager::component<Component3>; 

    Manager::addEntity(); 
    auto cmp2 = Manager::getComponent<Component2>(0); 

    Manager::removeEntity(0); 

    std::cin.get(); 
    return 0; 
} 

Как я могу перебрать конкретизированные компоненты для двух функций? Пробовал использовать вектор type_info для хранения типов Component, но я никогда не мог получить правильный тип из них для использования в качестве аргумента шаблона.

ответ

2

Вы можете начать использовать шаблон мета-программирования трюк до get a unique ID for your types. Тогда вы могли бы использовать карту с уникальными типами ids вместо ваших векторов переменных шаблона. Вводя полиморфизм с базовым классом Component, в сочетании с static_cast (для сокращения затрат времени выполнения), вы можете легко повторно реализовать предыдущие addComponent и методы getComponent. Из-за доступа к карте они будут немного более дорогостоящими, но в конце вы можете реализовать addEntity и removeEntity путем итерации по карте, выполняя именно то, что вы хотели.

Вот моя реализация указанных идей:

#include <vector> 
#include <map> 
#include <memory> 
#include <iostream> 

typedef void(*unique_id_type)(); 

template <typename... Arguments> 
struct IdGen { 
    static constexpr inline unique_id_type get_unique_id() 
    { 
     return &IdGen::dummy; 
    } 

private: 
    static void dummy() {}; 

}; 

class Component {}; 
class Component1 : public Component {}; 
class Component2 : public Component {}; 
class Component3 : public Component {}; 

class Manager { 
public: 
    static std::map<unique_id_type, std::vector<std::shared_ptr<Component>>> components; 

    template<typename T> static std::shared_ptr<T> getComponent(int nth) { 
     return std::static_pointer_cast<T>(components[IdGen<T>::get_unique_id()][nth]); 
    } 

    template<typename T> static std::shared_ptr<T> addComponent(int nth) { 
     return std::static_pointer_cast<T>(components[IdGen<T>::get_unique_id()][nth] = std::shared_ptr<T>(new T())); 
    } 

    static void addEntity() { 
     for (auto& component : components) 
      component.second.push_back(nullptr); 
    } 

    static void removeEntity(int nth) { 
     for (auto& component : components) 
      component.second[nth] = nullptr; 
    } 
}; 

std::map<unique_id_type, std::vector<std::shared_ptr<Component>>> Manager::components = { 
    { IdGen<Component1>::get_unique_id(), {} }, 
    { IdGen<Component2>::get_unique_id(), {} }, 
    { IdGen<Component3>::get_unique_id(), {} }, 
}; 

int main() { 
    Manager::addEntity(); 
    auto cmp2 = Manager::getComponent<Component2>(0); 

    Manager::removeEntity(0); 

    std::cin.get(); 
    return 0; 
} 

PS = Этот код использует C++ 11 функций, таких как constexpr и список инициализации, но так как вы уже использовали C++ 14 (даже если вы не помечал ваш вопрос как C++ 14), я думаю, что это не проблема.

PS 2 = Поскольку я сбрасываю статическую информацию, вам не следует использовать виртуальное наследование с вашими компонентами (см. why).

Смежные вопросы