他の回答に加えて、すべてのText
キーが既知の異なるリソースに一意に対応すると仮定すると、次のようなことができType
ます。
class BaseText
{
// constructors that take const char *, std::string, etc.
// .. whatever else you currently have in class Text
};
template<typename Type>
class Text : public BaseText
{
// constructors that take const char *, std::string, etc.
};
次に、次のように変更ResourceManager
します。
class ResourceManager
{
template<typename Type>
Type RetrieveResource( Text<Type> name );
};
これにはコンパイル時のポリモーフィズムが必要であることに注意してください。ただし、ユーザーが正しく型付けされたバージョンの を取得できる限りText<Type>
、引数を再度明示的に指定しなくても、それを使用して正しく型付けされたリソースを取得できることをType
意味します。通常の関数呼び出しのように。
可能なオブジェクトのセットを静的に宣言し、適切な型で初期化できる場合、これは簡単に機能Text<Type>
しますが、これはあなたの場合には当てはまりません。ただし、代わりに、ユーザーが実行時にそれらを作成できる必要がある場合は、作成する正しい型を知る必要があるため、問題を少し押し戻すだけです。ただし、同じ場合は十分に便利ですText<Type>
オブジェクトは何度も使用されます。
Text<Type>
あなたやクライアントが異なるオブジェクトを何らかのデータ構造に一緒に保存する必要がある場合も、運が悪いことに注意してくださいBaseText
。したがって、これはやや特殊なソリューションですが、物事がどのように構造化されているかによっては、役立つ可能性があります (コードをもっと見ないとわかりません)。
編集:以下のコメントによると、オブジェクトのタイプは、オブジェクトを挿入するときにクライアントによって決定されるように見えるため、次のようなことができる可能性があります。
class ResourceManager
{
BaseText PutResource( const BaseText& name, BaseResource& resource );
template<typename Type>
Text<Type> PutResource( const BaseText& name, Type& resource );
BaseResource& RetrieveResource( const BaseText& name );
template<typename Type>
Type& RetrieveResource( const Text<Type>& name );
};
したがって、クライアントは、後でリソースを取得するために、一意の型付きキー オブジェクトを保持する必要があります。にアップキャストしてタイプ消去することを選択した場合、BaseText
取得前にキーをダウンキャストするか、後でリソースをダウンキャストすることにより、タイプ情報を正しく回復する責任があります。
これは、とにかくやらなければならないことに加えて追加のオプションに過ぎないことに注意してください。タイプ固有でないキーを使用してリソースへのアクセスを提供したい場合、そうする唯一の方法は、非固有のリソースを返すことです。型 (つまりBaseResource
、boost::any
、boost::variant<...>
、またはそれらと同等のものの 1 つ。) ただし、 の型固有のサブクラスを作成するとBaseText
、まったく同じ構文を使用して (つまり、明示的なテンプレート パラメーターは必要ありません)、正しく型指定されたリソースを取得できます。さらに、これにより次の使用法が可能になります。
// tree is a resource of type `Tree`
auto key = manager.PutResource("Tree01", tree);
// ...
const BaseText& basekey = key; // lose type information
// ...
// these are all equivalent
Tree& tree = dynamic_cast<Tree&>(manager.RetrieveResource("Tree01"));
Tree& tree = dynamic_cast<Tree&>(manager.RetrieveResource(basekey));
Tree& tree = manager.RetrieveResource(key); // no casts required
Tree& tree = manager.RetrieveResource<Tree>("Tree01")
これらのdynamic_cast
バージョンは基本的に、これらのテンプレート化されたオーバーロードなしで行う必要があるものですが、他の 2 つのバージョンは、ランタイム コストなしでこのアプローチで使用できる追加オプションです。