1

我正在实现一种C++使用消息队列和消息类设计的通信机制。也就是说,存在一个方法的抽象父Message类和类。该类将消息发送到适当的消息队列,该队列由消息的类型确定。(也就是说,因为它发送到队列并被发送到)每种消息类型都将被创建为来自 的派生类。CommunicationCommunication::send(Message&)Communicationmessage_queueMsg1Queue_Msg1Msg2Queue_Msg2Message

主要是,我对自动创建队列感兴趣。也就是说,如果我决定添加一个新的消息类型类newMsg,那么添加消息队列的过程Queue_newMsg将不需要更改Communication类中的代码,例如为每种消息类型创建队列的代码。

由于这可以在编译时完成(在编译时,所有派生消息类都是已知的,因此需要的消息队列),我正在尝试考虑一些元编程解决方案,但没有设法找到这样的解决方案。

使用一些已知的 MPL,例如boost/mpl,我怎样才能实现上述目标?

4

2 回答 2

1

您可以在运行时注册不同的消息类型,而不是依赖于元编程。注册表可以创建队列向量并提供唯一标识符以最小化查找成本,或者如果您不太关心这一点,您可以始终使用从某个 id 到适当队列的映射。

虽然我不推荐它,但如果您真的想编写一个复杂的模板解决方案,您可以查看类型列表。您需要的所有构建块都在Alexandrescu 的Modern C++ Design中(类型列表,如何从中构建层次结构,以及一些花哨的模板技巧)。

于 2013-04-16T17:56:20.950 回答
1

将您的类型打包到一个列表中:

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

使用该列表和参数包解包来创建std::array队列。如果您希望队列本身被专门键入,它们将需要位于tuple.

上面的列表暗示了索引和类型之间的双射。让每种类型的实例返回索引,您可以使用它来获取队列(在数组中,很容易 -- 在 a 中tuple,需要更多工作)。

一个index_of特征类,用于在 a 中查找类型的T索引type_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> 
{};

可能实现一个基于 CRTP 的“消息助手”,它同时实现GetTypeIndex并确保您的类型位于中央消息列表中。

这需要 C++11,在 C++03 中更难,也更受限制。C++11 编译器也将处理 100 种类型,而无需进行太多额外的模板元编程(严重的元编程,至少在理论上,1000 或更多),而 C++03 编译器即使具有强大的元编程库也可能仅限于10 种类型。

请注意,这种方法的一个优点是,理论上,您可以完全取消抽象父类,或者至少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 回答