在模板类中为纯虚函数提供默认实现

时间:2019-08-28 08:53:26

标签: c++ c++17

我有一个模板类,实现了一种调度程序:该类处理具有“键”的“消息”,并且键的一部分用于确定将消息传递至的“处理程序”。用户必须从模板类派生并提供从“键”到用于分发的键部分的映射。我认为纯虚拟函数是建模的自然方法:

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提供默认实现:

  1. 在最简单的情况下,KeyPortiontypename Message::key_type相同,所以我可以提供:

    virtual KeyPortion toHandlerKey(typename Message::key_type key) {
        return key;
    }
    
  2. 在大多数情况下,Message::key_type是包含std::tuple的{​​{1}},所以我可以提供:

    KeyPortion

但是我不知道如何正确编写。我不能使用virtual KeyPortion toHandlerKey(typename Message::key_type key) { return std::get<KeyPortion>(key); } ,因为我没有试图重载任何东西。我也不能提供全面的实现,因为那样的话,用户可能会忘记覆盖它。

总而言之,我希望模板类提供其中一棵树:

  1. 上述情况(1)的简单虚拟实现;
  2. 上述情况(2)的简单虚拟实现;
  3. 一个纯虚拟函数,它将迫使用户定义自己的实现。

有没有办法做到这一点?

1 个答案:

答案 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 */
};

例如,公共部分可以通过基类分解。