1

C++メッセージキューとメッセージクラスで設計された通信メカニズムを実装しています。つまり、メソッドが存在する抽象的な親Messageとクラスです。このクラスは、メッセージのタイプによって決定される適切なメッセージ キューにメッセージを送信します。(つまり、キューに送信され、 に送信されるため) 各メッセージ タイプは、 からの派生クラスとして作成されます。CommunicationCommunication::send(Message&)Communicationmessage_queueMsg1Queue_Msg1Msg2Queue_Msg2Message

主に、キューの作成を自動化することに興味があります。つまり、新しいメッセージ タイプ クラスを追加することにした場合newMsg、メッセージ キューを追加するプロセスでは、メッセージ タイプごとにキューを作成するコードなど、クラスQueue_newMsg内のコードを変更する必要はありません。Communication

これはコンパイル時に実行できるため (コンパイル時に、すべての派生メッセージ クラスが既知であり、必要なメッセージ キューもわかっているため)、メタプログラミングの解決策を考えようとしていますが、そのような解決策を見つけることができませんでした。

などの既知のMPLを使用してboost/mpl、どうすれば上記を達成できますか?

4

2 に答える 2

1

タイプをリストにパックします。

template<typename... Ts>
struct type_list {};

そのリストとパラメーター パックのアンパックを使用して、一連std::arrayのキューを作成します。キュー自体を具体的にタイプしたい場合は、tuple.

上記のリストは、インデックスとタイプの間の全単射を意味します。各タイプのインスタンスがインデックスを返すようにします。これを使用してキューを取得できます (配列では簡単ですが、 atupleでは、より多くの作業が必要です)。

型のインデックスを見つけるためのindex_of特性クラス:Ttype_list<Ts...>

template<typename T, typename list, typename=void>
struct index_of {};

template<typename T, typename T0, typename... Ts>
struct index_of<T, type_list<T0, Ts...>, 
                typename std::enable_if<std::is_same<T, T0>::value>::type
               > :  std::integral_constant<size_t, 0> 
{};

template<typename T, typename T0, typename... Ts>
struct index_of<T, type_list<T0, Ts...>, 
                typename std::enable_if<!std::is_same<T, T0>::value>::type
               > :  std::integral_constant<size_t, 
                                   index_of<T, type_list<Ts...>>::value+1> 
{};

おそらく両方を実装GetTypeIndexし、あなたのタイプが中央のメッセージリストにあることを保証するCRTPベースの「メッセージヘルパー」を実装してください。

これには C++11 が必要ですが、C++03 ではより難しく、より制限されています。C++11 コンパイラは、追加のテンプレート メタプログラミングをあまり行わずに (少なくとも理論的には、1000 以上の本格的なメタプログラミングを使用して) 何百もの型を処理しますが、C++03 コンパイラは、堅牢なメタプログラミング ライブラリを使用する場合でも、制限される可能性があります。数十種類。

このアプローチの利点は、理論的には、抽象親クラスを完全に、または少なくともsendMessage( message const& m )インターフェースを廃止できることです (なぜ人々が抽象メッセージを送信できるようにする必要があるのでしょうか?)。実際の具体的なメッセージ タイプの送信のみが許可される可能性があります。この場合も、さらに作業が必要です (CRTP を使用してキューを取得するパック拡張継承ツリーを作成します)。

struct MessageBase {
  virtual size_t GetTypeIndex() const = 0;
};
template<typename D, typename List>
struct MessageHelper: public MessageBase {
  static_assert( std::is_base_of< MessageHelper<D,List>, D >::value, "MessageHelper<D> must be inherited from by D" );
  D* self() { return static_cast<D*>(this); }
  D const* self() const { return static_cast<D const*>(this); }
  virtual size_t GetTypeIndex() const final override {
    return index_of<D,List>::value;
  }
};

struct A_Queue {
  std::deque< std::unique_ptr<MessageBase> > data;
};

template<typename type_list>
struct MessageQueues;

template<typename... Ts>
struct MessageQueues<type_list<Ts...>> {
  std::array< A_Queue, sizeof...(Ts) > queues;
  void Enqueue( std::unique_ptr<MessageBase> msg ) {
    size_t index = msg->GetTypeIndex();
    queues[ index ].data.push-back( std::move(msg) );
  }
};

真剣に大まかなドラフトの実装のために。

于 2013-04-16T18:13:16.967 に答える