我有一个模板类,实现了一种调度程序:该类处理具有“键”的“消息”,并且键的一部分用于确定将消息传递至的“处理程序”。用户必须从模板类派生并提供从“键”到用于分发的键部分的映射。我认为纯虚拟函数是建模的自然方法:
template<typename Key>
class Message {
public:
using key_type = Key;
/* more stuff which is irrelevant */
};
template<typename Message, typename KeyPortion, typename Handler>
class Dispatcher {
public:
virtual KeyPortion toHandlerKey(typename Message::key_type) = 0;
/* a bit more stuff which is irrelevant */
};
用户被强制派生,并被强制重写功能。很好。
现在,在几种情况下,我可以为toHandlerKey
提供默认实现:
在最简单的情况下,KeyPortion
与typename Message::key_type
相同,所以我可以提供:
virtual KeyPortion toHandlerKey(typename Message::key_type key) {
return key;
}
在大多数情况下,Message::key_type
是包含std::tuple
的{{1}},所以我可以提供:
KeyPortion
但是我不知道如何正确编写。我不能使用virtual KeyPortion toHandlerKey(typename Message::key_type key) {
return std::get<KeyPortion>(key);
}
,因为我没有试图重载任何东西。我也不能提供全面的实现,因为那样的话,用户可能会忘记覆盖它。
总而言之,我希望模板类提供其中一棵树:
有没有办法做到这一点?
答案 0 :(得分:2)
您可以使该类对SFINAE友好,然后提供专门化:
template<typename Message, typename KeyPortion, typename Handler, typename Enabler = void>
class Dispatcher {
public:
virtual KeyPortion toHandlerKey(typename Message::key_type) = 0;
/* a bit more stuff which is irrelevant */
};
template<typename Message, typename KeyPortion, typename Handler>
class Dispatcher<Message,
KeyPortion,
Handler,
std::enable_if_t<std::is_same<KeyPortion, typename Message::key_type>>>
{
public:
virtual KeyPortion toHandlerKey(typename Message::key_type key)
{
return key;
}
/* a bit more stuff which is irrelevant */
};
template<typename Message, typename KeyPortion, typename Handler>
class Dispatcher<Message,
KeyPortion,
Handler,
std::void_t<decltype(std::get<KeyPortion>(std::declval<typename Message::key_type>()))>>
{
public:
virtual KeyPortion toHandlerKey(typename Message::key_type key)
{
return std::get<KeyPortion>(key);
}
/* a bit more stuff which is irrelevant */
};
例如,公共部分可以通过基类分解。