2016-07-06 4 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

ComponentManagerprivateメンバ関数テンプレートを追加します。

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メンバ関数テンプレートを持つことができます。次に、コンポーネントタイプを指定して適切なコレクションを取得するためのコードを追加する必要があります。その1つの方法は、タグディスパッチ機構を使用することです。このアプローチで

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; 
}; 

、あなたはまだあなたがサポートしたいが、彼らはクラスではなく、publicprivateセクションになりますComponentの種類ごとにクラスに他のメンバ関数を追加する必要があります。

+0

コンポーネントコレクションをパラメータとして渡すことはやや面倒で危険です。追加するコレクションは、常にそのタイプのメンバーコレクションです。これは、そのコレクションを公開する必要があり、別のコレクション(同じタイプであるがComponentManagerのコレクションではないコレクション)で呼び出されるリスクを実行します。 – ROX

+1

@ROXの場合、内部関数はプライベートになります。間違ったコンポーネントを渡そうとすると、コンパイルエラーとなり、実行時エラーにはなりません。 – SirGuy

+0

プライベートであれば、正しいコレクションを渡すタイプごとにパブリックバージョンなしで呼び出すことはできません。それで、クラスはそれぞれのタイプに似た機能をたくさん持っていることに戻ります。これはOPが避けようとしているものです。 – ROX

0

あなたは1つの汎用タイプ

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; 
}; 

を処理し、これらすべての管理職

struct ComponentManager 
{ 
    ComponentManagerT<PositionComponent> m_positionComponentManager; 
    ComponentManagerT<VelocityComponent> m_velocityComponentManager; 
}; 
関連する問題