2016-07-06 57 views
0

我正在通過編寫遊戲來學習C++,並且遇到了一些問題:我有一個開始重複的代碼(我將添加一些其他組件),並且我想使用模板來改進它(我猜),我真的不知道如何使用。模板的使用

下面的代碼:

#include <memory> 

#include "PositionComponent.h" 
#include "VelocityComponent.h" 

class ComponentManager 
{ 
public: 
    ComponentManager(); 

    void addComponent(Entity id, PositionComponent component); 
    void addComponent(Entity id, VelocityComponent component); 

private: 
    std::map<Entity,std::shared_ptr<PositionComponent> > m_positionComponents; 
    std::map<Entity,std::shared_ptr<VelocityComponent> > m_velocityComponents; 
}; 

#include "ComponentManager.h" 

ComponentManager::ComponentManager() 
{ 

} 

void ComponentManager::addComponent(Entity id, PositionComponent component) 
{ 
    if (m_positionComponents.count(id) > 0) 
    { 
     Tools::log("couldn't add component"); 
    } 
    // else if entity doesn't exist.. 
    else 
    { 
     m_positionComponents[id] = std::make_shared<PositionComponent>(component); 
    } 
} 

void ComponentManager::addComponent(Entity id, VelocityComponent component) 
{ 
    if (m_velocityComponents.count(id) > 0) 
    { 
     Tools::log("couldn't add component"); 
    } 
    // else if entity doesn't exist.. 
    else 
    { 
     m_velocityComponents[id] = std::make_shared<VelocityComponent>(component); 
    } 
} 

如何使與模板的美麗?

謝謝!

+0

一個模板類,也許嘗試代碼審查:HTTP://codereview.stackexchange。com/ –

+0

覺得你最好使用繼承,而不是模板 – yizzlez

+0

@awesomeyi或靜態多態,其中包括模板再次;-) ... –

回答

1

我覺得在這裏使用模板很好,其他選項肯定存在。這裏是我想嘗試的模板解決方案:

template <class T> 
void ComponentManager::addComponent(Entity id, T component) 
{ 
    using MapType = std::map<Entity,std::shared_ptr<T> > &; 
    auto allMaps = std::tie(m_positionComponents, m_velocityComponents); 
    auto & tMap = std::get<MapType>(allMaps); 
    if (tMap.count(id) > 0) 
    { 
     Tools::log("couldn't add component"); 
    } 
    // else if entity doesn't exist.. 
    else 
    { 
     tMap[id] = std::make_shared<T>(component); 
    } 
} 

這沒有經過測試,所以我不保證它會按原樣編譯。

此處使用的std::get的過載需要c++-14

+0

它很好,謝謝:) – Urefeu

0

如何使模板變得美觀?

溶液1

添加private成員函數模板ComponentManager

template <typename Component> 
    void addComponent(Entity id, 
        Component component, 
        std::map<Entity,std::shared_ptr<Component> >& components) 
    { 
    if (components.count(id) > 0) 
    { 
     Tools::log("couldn't add component"); 
    } 
    // else if entity doesn't exist.. 
    else 
    { 
     components[id] = std::make_shared<Component>(component); 
    } 
    } 

,並用它作爲:

void ComponentManager::addComponent(Entity id, PositionComponent component) 
{ 
    this->addComponent(id, component, m_positionComponents); 
} 

void ComponentManager::addComponent(Entity id, VelocityComponent component) 
{ 
    this->addComponent(id, component, m_velocityComponents); 
} 

這種方法的缺點是,對於每一種要支持Component,你需要添加另一個public成員函數。

解決方案2

你只能有一個public成員函數模板組件添加到相應的集合。然後,您需要添加代碼以獲取給定組件類型的正確集合。一種方法是使用標籤分派機制。

class ComponentManager 
{ 
    public: 
     ComponentManager(); 

     template <typename Component> 
     void addComponent(Entity id, Component component) 
     { 
      std::map<Entity,std::shared_ptr<Component> >& components = getCollection(tag<Component>()); 
      if (components.count(id) > 0) 
      { 
       Tools::log("couldn't add component"); 
      } 
      // else if entity doesn't exist.. 
      else 
      { 
       components[id] = std::make_shared<Component>(component); 
      } 
     } 

    private: 

     template <typename Component> struct tag {}; 

     std::map<Entity,std::shared_ptr<PositionComponent> >& getCollection(tag<PositionComponent>) 
     { 
     return m_positionComponents; 
     } 

     std::map<Entity,std::shared_ptr<PositionComponent> >& getCollection(tag<VelocityComponent>) 
     { 
     return m_velocityComponents; 
     } 

     std::map<Entity,std::shared_ptr<PositionComponent> > m_positionComponents; 
     std::map<Entity,std::shared_ptr<VelocityComponent> > m_velocityComponents; 
}; 

通過這種方法,你仍然需要另一個成員函數添加到類你想支持每種類型的Component但他們會在課堂上,不publicprivate部分。

+0

將組件集合作爲參數傳遞有點繁瑣且是一種風險。要添加到的集合始終是該類型的成員集合。這需要公開該集合,並冒着被另一個集合調用的風險,這個集合是一個類型相同但不是ComponentManager中的集合。 – ROX

+1

@ROX,內部函數將是私有的,如果您嘗試傳遞錯誤的組件,它將是編譯錯誤,而不是運行時錯誤。 – SirGuy

+0

如果它是私人的,你不能在沒有公開版本的情況下爲每種類型通過正確的收集。隨着這個類的迴歸,每種類型都有許多類似的功能,這正是OP試圖避免的。 – ROX

0

您可以創建一個處理一個泛型類型

template <typename T> 
class ComponentManagerT 
{ 
public: 
    void addComponent(Entity id, T component) 
    { 
     if (m_components.count(id) > 0) 
     { 
      Tools::log("couldn't add component"); 
     } 
     // else if entity doesn't exist.. 
     else 
     { 
      m_components[id] = std::make_shared<T>(component); 
     } 
    } 

    // ... 
private: 
    std::map<Entity, std::shared_ptr<T>> m_components; 
}; 

和A類重新集結所有這些經理

struct ComponentManager 
{ 
    ComponentManagerT<PositionComponent> m_positionComponentManager; 
    ComponentManagerT<VelocityComponent> m_velocityComponentManager; 
};