C ++テンプレートのリターン
-
18-09-2019 - |
質問
私は「コンポーネント」を開催し、「エンティティ」、(FTW構図)上に構築されたプログラムを持っています。
コンポーネントなどのスクリプト、資産、などの多くの異なる種類を含むことができ、私は
と呼ばれるエンティティの機能を構築したいと思いますエンティティは、コンポーネントタイプの名前で検索することができるような文字列のマップ、および実際のコンポーネントを、持っています。
私はと呼ばれる機能を持っていると思います。
<Component T>GetComponent(char* TypeName, <T>);
文字列と型名を取り込み、これは、要求された型指定されたコンポーネントを返します。
これは、C ++テンプレートを使用して、このようなことを行うことは可能ですか?上記は明らかに動作しない、と私はそれについて移動するかどうかはわかりません。
おかげ
編集ます:
私は工場を探していませんよ。
エンティティは、コンポーネントのさまざまなタイプのインスタンスを保持しています。現在、これがで行われます。
std::vector<Component> componentList;
と
std::vector<char*> componentNames;
誰のインデックスと同じであることが保証されています。おそらく私は、後に適切なマップを作成します。
私は単にGetComponentがComponentListにエンティティが保持しているタイプ名のすでにinstantiedコンポーネントを適切に型指定された参照を返すようにしたい。
解決
あなたの関数は、ののコンポーネントを作成していますか?そして、それは工場です。あなたはクライアントに(潜在的に誤った)鋳造を節約するために、そのテンプレートでそれをラップすることができます。
関数テンプレートの種類は次のようになります:
template< typename T >
T* GetComponent(const char*); // presuming it returns a pointer
と、それは次のように呼び出されます。
Foo* foo = GetComponent<Foo>("foo");
他のヒント
適切な質問をすることは良い答えを得るための方法の少なくとも半分です。あなたは本当にあなたが直面している特定の問題ではなく、達成したいものを必ず明記してください。あなたが実際に実現するよりも、言語に多くの問題を抱えているかのように私には思える。
最初の部分は、おそらく共通のインターフェースを提供する、Componentから派生コンポーネント階層構造を持っているかのように思われることです。エンティティは、コンポーネントからの派生型であることができ、内部で多くのコンポーネントを、保持しています。その場合は、あなたが直接コンポーネントオブジェクトを格納しているとして、あなたはあなたのコンテナを手直しする必要があり、それはあなたのオブジェクトにスライスを生成します(派生どんな関係なく、あなたは、コンテナの中に入ると入力、コンテナは唯一の共通コンポーネントの一部を維持しますオブジェクト)。
ベクトルのカップルに取り組んでおり、それらの両方が常に同期されますことを期待することは可能しかし、壊れやすいです。名前とコンポーネントが一緒に行く場合は、名前/コンポーネントのペアを格納します。名前で検索する場合、それはO(Nを記録)を提供しますと、あなたが直接検索するマップを使用する必要があります。
さて、戻って質問に行きます。何を達成したいことは無地のシンタックスシュガーである場合には(必要に応じて明示的にダイナミックキャストからの発信者を避けるため)、その後、テンプレート(もっと後で)でそれを得ることができます。しかし、あなたは本当にあなたのデザインに考えなければなりません。コンポーネントは、任意のコンポーネントに実際のインタフェースを定義していますか?ユーザーがコンポーネントを使用する前に、特定の型にダウンキャストする必要があり、どちらかの抽象化が悪い場合(Componentが実際のインターフェイスを提供していません)、またはオブジェクトが実際に一緒に適合しない。
それの終わりに、あなたはまだそれをしたい場合は、は、テンプレートメソッド(またはフリー機能)以内にそれを実行して、発信者からの動的キャストを非表示にすることができます。
class Entity {
typedef std::map< std::string, boost::shared_ptr<Component> > component_map_t;
public:
boost::shared_ptr<Component> getComponent( std::string const & name ) {
component_map_t::iterator it = components_.find(name);
if ( it == components_.end() ) { // not found, handle error
// ...
}
return it->second;
}
template <typename T> // syntactic sugar
boost::shared_ptr<T> getComponent( std::string const & name ) {
return boost::dynamic_pointer_cast<T>( getComponent(name) );
}
private:
component_map_t components_;
};
template <typename T> // syntactic sugar also available as free function
boost::shared_ptr<T> getComponent( Entity & entity, std::string const & name ) {
return boost::dynamic_pointer_cast<T>( entity.getComponent(name) );
}
int main() { // usage
Entity e; // ... work with it add components...
boost::shared_ptr<Component> c1 = e.getComponent( "one" ); // non-templated method returns Component
boost::shared_ptr<DerivedComponent> c2 = e.getComponent<DerivedComponent>( "two" );
boost::shared_ptr<DerivedComponent> c3 = getComponent<DerivedComponent>( e, "two" );
}
代わりにboost::shared_ptr
のあなたが(:ユーザーコードは、コンポーネントがエンティティから削除された場合ダングリングリファレンスを使用しようとしないように、寿命が慎重に制御しなければならない、それが伴うものと)実際の参照を返すようにあなたはインターフェースで遊ぶことができますます。
あなたのようなものを使用することができます:
struct Entity
{
Component* GetBaseComponent (const char* TypeName)
{
// do lookup on TypeName and return corresponding Component.
}
template<typename T> T* GetComponent (const char* TypeName)
{
return dynamic_cast<T*> (GetBaseComponent (TypeName));
}
};
とのようなものでそれを呼び出します:
entity.GetComponent<MyComponent> ("MyComponent");
あなたがコンポーネントを頼むと、間違った型を取得した場合は、キャストはヌルPTRを返します。
の編集のジャストこれは工場出荷時にそれを呼び出さずにいえ、基本的にSBIと同じソリューションで実現
。あなたのgetComponent関数は、2つの別々のタスクを持っている。
1)文字列識別子からオブジェクトを取得
2)
提供テンプレート引数の型にこのオブジェクトをキャストテンプレートを使用すると、(2)かなりまっすぐ進むことができます。しかし、(1)文字列オブジェクトの作業が必要なので、テンプレートは自分でトリックを行うことはありません。あなたの部品容器の他の方法を埋めるために持っています。保存および鋳造用として、あなたはどの::ブーストに興味があってもよいし、後押し::バリアントを。