将您的类型打包到一个列表中:
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) );
}
};
对于一个非常粗略的实施草案。