我正在C++
中实现一个使用消息队列和消息类设计的通信机制。也就是说,抽象父Message
和类Communication
,其中存在方法Communication::send(Message&)
。类Communication
将消息发送到适当的消息队列message_queue
,该队列由消息的类型确定。
(也就是说,对于Msg1
,它会发送到队列Queue_Msg1
,Msg2
会发送到Queue_Msg2
)
每个消息类型都将创建为Message
的派生类。
主要是,我感兴趣的是自动创建队列。也就是说,如果我决定添加新的消息类型类newMsg
,添加消息队列Queue_newMsg
的过程将不需要在Communication
类中更改代码,例如代码创建每种消息类型的队列。
因为这可以在编译时完成(在编译时,所有派生的消息类都是已知的,所以需要的消息队列),我试图想到一些元编程解决方案,但没有设法找到这样的。
使用某些已知的MPL,例如boost/mpl
,我该如何实现上述目标?
答案 0 :(得分:1)
您可以在运行时注册不同的消息类型,而不是依赖于元编程。注册表可以创建一个队列向量并提供唯一标识符以最小化查找成本,或者如果您不太关心它,您可以始终使用某个id的映射到适当的队列。
虽然我不推荐它,但如果您真的想编写复杂的模板解决方案,可以查看类型列表。您需要的所有构建块都在Alexandrescu的 Modern C ++ Design 中(类型列表,如何从中构建层次结构,以及一些花哨的模板技巧)。
答案 1 :(得分:1)
将您的类型打包到列表中:
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 )
接口(为什么要允许人们发送抽象消息?)。您只能被允许发送实际的具体消息类型。这又需要更多的工作(你创建了包扩展的继承树,它使用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) );
}
};
执行粗略草案。