0

したがって、基本的にはタイプを説明するメタデータ (文字列などの基本的なメタデータ) を持つ void* オブジェクトの辞書であるリソース マネージャーがあります。現在、オブジェクトを返すテンプレート メソッドがあります。

class ResourceManager
{
    template<typename Type>
    Type RetrieveResource( Text name );
};

私の質問は、このメソッドをテンプレート メソッドではなくするにはどうすればよいですか? 末尾の戻り値の型とそのファンキーな構文の使用について調査しました。アイデアは、ある時点でデータを正しい型として取得し、エンドユーザー側で追加のキャストを行わずにその型としてデータを返したいということです。

私はこのようなものを撮影しています:

auto RetrieveResource( Text name)
{
    return _dictionary[ name ]; // There's more to this, but imagine it returns varying type objects.
}

Boost::Any 型のオブジェクトを実装することを考えましたが、ちょっと複雑です (怠け者というわけではありません)。エンド ユーザー側でテンプレート構文を回避しようとしています。

どんな助けでも素晴らしいでしょう。また、バリアントやその他 (プロジェクト仕様) などの Boost ライブラリ構造を使用することもできません。前もって感謝します!

ここで魔法を求めているのは理解していますが、それが S/O の目的であると考えました: 魔法を見つけることです。それが不可能なら、私は理解しています。しかし、誰かが革新的なソリューションを持っていれば、それは素晴らしいことです.

4

3 に答える 3

1

他の回答に加えて、すべての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取得前にキーをダウンキャストするか、後でリソースをダウンキャストすることにより、タイプ情報を正しく回復する責任があります。

これは、とにかくやらなければならないことに加えて追加のオプションに過ぎないことに注意してください。タイプ固有でないキーを使用してリソースへのアクセスを提供したい場合、そうする唯一の方法は、非固有のリソースを返すことです。型 (つまりBaseResourceboost::anyboost::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 つのバージョンは、ランタイム コストなしでこのアプローチで使用できる追加オプションです。

于 2013-03-19T18:12:29.410 に答える
0

最良の選択は、基本クラスのポインターを返すことだと思います。マイナスは、誰もがそこから派生することを強制することですが、基本クラスのスマートなアーキテクチャでは、より多くのプラスがある可能性があります

于 2013-03-19T17:57:30.463 に答える
0

あいまいすぎるのではないかと心配しています。戻り値の型でオーバーロードすることはできず、戻り値の型として使用することはできませんauto

于 2013-03-19T17:45:35.340 に答える