2016-11-08 90 views
0

我正在修改实体组件系统的实体管理器。由于组件没有重叠的功能,我不希望它们拥有我可以存储的共享基础。跟踪实例化的模板类型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的向量来存储组件类型,但我永远无法从它们中获取适当的类型以用作模板参数。

回答

2

您可以从get a unique ID for your types开始使用模板元编程技巧。 然后,您可以使用带有唯一类型ID的地图来代替您的可变模板向量。通过引入基类组件类的多态性,再加上static_cast(以降低运行时成本),您可以轻松地重新实现以前的addComponentgetComponent方法。由于地图访问,它们的成本会稍高一些,但最终您可以通过遍历地图来实现addEntityremoveEntity,完全按照您的要求进行。

下面是我实现的上述观点:

#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 =因为我是使用static_cast向下转换的,所以您不应该对组件使用虚拟继承(请参阅why)。