我正在C++中实现一种通信机制,该机制是为消息队列和消息类设计的。即,一个抽象父Message和类Communication,其中存在一个方法Communication::send(Message&)。类Communication将消息发送到适当的消息队列message_queue,该队列由消息的类型确定。
(也就是说,对于Msg1,它发送到队列Queue_Msg1,而Msg2发送到Queue_Msg2)
每个消息类型都将创建为Message的派生类。

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

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

使用一些已知的MPL(例如boost/mpl),如何实现以上目标?

最佳答案

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

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

使用该列表和参数包解包来创建队列的std::array。如果您要专门指定队列本身,则它们需要在tuple中。

上面的列表暗示了索引和类型之间的双射。让每种类型的实例返回索引,您可以使用该索引来获取队列(在数组中,简单-在tuple中,需要更多工作)。
index_of traits类,用于在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编译器甚至具有强大的元编程库也可能限于10s类型。

请注意,此方法的优点是,从理论上讲,您可以完全取消抽象父类,或者至少取消sendMessage( message const& m )接口(interface)(为什么应该允许人们发送抽象消息?)。您可能只被允许发送实际的具体消息类型。这再次需要做更多的工作(您创建使用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) );
  }
};

认真执行草案。

关于c++ - 使用元编程进行消息队列管理,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16043622/

10-11 20:49
查看更多