2016-11-08 87 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)。