我正在用 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 编译器即使具有强大的元编程库也可能仅限于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/