c++ - 使用元编程进行消息队列管理

标签 c++ metaprogramming template-meta-programming

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

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

因为这可以在编译时完成(在编译时,所有派生的消息类都是已知的,因此需要消息队列),我试图想出一些元编程解决方案,但没有成功找到这样的。

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

最佳答案

将类型打包到列表中:

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

使用该列表和参数包解包创建一个 std::array队列。如果您希望队列本身具有特定类型,则它们需要位于 tuple 中。 .

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

index_of traits 类,查找类型的索引 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> 
{};

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

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

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

相关文章:

c++ - 使用 C++ xerces 库时出现异常 "node is used in a different document than the one that created it"

c++ - 我们如何将带有类模板的友元函数声明到 .h 文件中并将它们定义到 .cpp 文件中(不是全部在一个头文件中)?

c++ - opencv无法加载jp2图像文件

Ruby eigenclass(单例类)创建了吗?为了哪个?

c++ - Boost.Fusion 运行时开关

c++ - 期望一个类型,得到一个模板

c++ - 尝试将参数包的第一个元素作为函数调用并将包的其余部分作为参数传递给它

c++ - 从函数参数构建模板?

c++ - 检查可调用模板参数类型

c++ - 在我的案例中,我是否需要销毁单例实例?