2017-07-21 7 views
1

時にIDを持つオブジェクトを取得するのは、我々は次のオブジェクトを持っているとしましょう:C++ランタイム

struct A{ 
    static const int ID = 1; 
}; 

struct B{ 
    static const int ID = 2; 
}; 

struct C{ 
    static const int ID = 3; 
}; 

struct D{ 
    static const int ID = 4; 
}; 

struct Collection{ 
    std::vector<A> o1; 
    std::vector<B> o2; 
    std::vector<C> o3; 
    std::vector<D> o4; 
}; 

Collection collection; 

私は何をしたいことはCollectionvector Sの一部への参照を取得しています。これらを取得するには、次の3つの方法があります。

  1. タイプ別には、vectorです。 collection.get<A>();

  2. コンパイル時のIDは、vectorによって保持されているすべてのオブジェクトによって定義されます。 collection.get<4>();

  3. IDは実行時にIDで指定します。 collection.get(id);

ケース1は、ケース2に変換できるので、T::IDで簡単です。ケース2は、テンプレートの特殊化で実装できます(ただし、オブジェクトがたくさんある場合は醜いです)。 ケース3が大変困っています。いくつかの巨大なifまたはswitchのステートメントがなければ、それはほとんど不可能であると肩代わりします。

私の質問は以下のとおりです。

  • ケース2は、よりエレガントにする方法はありますか?
  • ケース3はどのように実装する必要がありますか?
+0

常に「A、B、C、D」しかありませんか? –

+0

おそらくいいえ、少なくとも30があります。 – Overblade

+0

あなたはランタイム値を持っています。あなたはそれが何であるか分からない。その値に応じて異なるタイプの演算を行う必要があります。つまり、同じ関数テンプレートの異なるインスタンス化であっても、まったく異なるコードパスを意味します。つまり、ランタイムブランチを意味します。だから、あなたは 'switch'や' map 'のいずれかを持っています。 – Useless

答えて

1

あなたができることとできないことがあります。あなたが求めているのはそれほど簡単ではなく、苦労することです。

1および2は困難ですが、達成可能です。まず、create a static map of all type-IDs、次にuse the static result to choose the type

今3 ...よく...申し訳ありませんが不可能です!私が言っていることを証明する反例を提供する:実行時に戻り値の型を選択する関数を決して作成することはできません。しかし...

LLVMの人々がdynamic_castを取り除くためにしたことは基本的に何かできることがありますが、あまりにも多くのコードです。

まず、ケースベース抽象クラス、およびするすべてのこれらのクラスはそれから派生し、それはIDが含まれています

struct Base{ 
    virtual int getClassID() = 0; 
    static Base* CreateObject(int ID) //consider using shared_ptr here 
     { 
     switch(ID) { 
     case A::ID: 
      return new A; 
     }    
     case B::ID: 
      return new B; 
     default: 
      return nullptr; 
     } 
     //... 
    } 
} 

struct A : public Base { 
    static const int ID = 1; 
    int getClassID() override { 
     return ID; 
    } 
}; 

struct B : public Base { 
    static const int ID = 2; 
    int getClassID() override { 
     return ID; 
    } 
}; 

struct C : public Base { 
    static const int ID = 3; 
    int getClassID() override { 
     return ID; 
    } 
}; 

struct D : public Base { 
    static const int ID = 4; 
    int getClassID() override { 
     return ID; 
    } 
}; 

は、新しいクラスをインスタンス化するために、あなたはあなたの基本クラスを使用します。今

Base* c = Base::CreateObject(3); //object of C 

、最終的には、あなたの魔法のキャスト演算子を作成:

template <typename T> 
T* MyMagicCast(Base* obj) 
{ 
    if(obj->getClassID() ISVALID) //Then use the ID to make sure that T matches the ID 
    { 
     return static_cast<T*>(obj); 
    } 
    else 
    { 
     return nullptr; 
    } 
} 

をそして、これはあなたのためのランタイムのものを行います。このメソッドを使用すると、すべてのタイプの操作がベース+を呼び出すことによって実行できるという利点があります。+あなたはRTTIを使用していません。あなたが持っているタイプ(A、B、C、D)に固有のものが必要な場合にのみMyMagicCast()を使用して型にキャストします。

PS:コードが頭の上から外れているため、タイプミスやエラーが発生する可能性があります。

+0

あなたの例をありがとう、私はそれを見てみましょう。 – Overblade