在可变参数类模板中覆盖多个虚拟功能

时间:2019-03-01 09:24:19

标签: c++ variadic-templates

让我给一个例子。

#include <iostream>
#include <utility>
#include <tuple>

template <typename Service>
struct SubscriberImpl {
    virtual void handleService(Service const&) = 0;
};

template <typename...ServiceType>
struct Subscriber : SubscriberImpl<ServiceType>... {

};

struct IntService {};
struct FloatService {};

template <typename StatusUpdatePolicy, typename... ServiceType>
struct StatusUpdater : Subscriber<ServiceType...>
{
    StatusUpdater(StatusUpdatePolicy const& statusUpdater)
    : m_statusUpdater{statusUpdater}
    {}
    // wont work
    void handleService(IntService const& service) override {
        m_statusUpdater.updateService(service);
    }

    void handleService(FloatService const& service) override {
        m_statusUpdater.updateService(service);
    }

    StatusUpdatePolicy m_statusUpdater;
}; 

struct DummyPolicy {
    void updateService(IntService const& service) {
        m_i = 42;
        std::cout << m_i << "\n";
    }

    void updateService(FloatService const& service) {
        m_f = 3.14f;
        std::cout << m_f << "\n";
    }

    int m_i;
    float m_f;
};
int main() {

    StatusUpdater<DummyPolicy, IntService, FloatService> su(DummyPolicy{}); 

    su.handleService(IntService{});
    su.handleService(FloatService{});
}

Subscriber中,包handleService(ServiceType const)中的每个模板参数都有一个纯虚函数ServiceType...。因此,我必须覆盖StatusUpdater上的每一个。在这里,我已经手动提供了IntServiceFloatService所需的那些,知道在这个最小的示例中我只需要那些。但是我希望能够为包ServiceType...中的内容提供一个替代。无论如何,它们都会调用给定策略的updateService方法。

请注意,Subscriber来自外部库,我无法修改其定义。

2 个答案:

答案 0 :(得分:5)

您不能将此类实现直接放入类中,而必须继承它们(类似于Subscriber从多个SubscriberImpl实例中继承的方式)。但是,要覆盖它们,并仍然使您的类可作为Subscriber多态使用,则必须“顺序”继承它们,而不是“并行”继承它们。另外,Curiously recurring template pattern可用于为所有实现提供对最终覆盖对象的访问权限:

template <class Self, class SubscriberClass, class... ServiceTypes>
struct StatusUpdaterOverride;


template <class Self, class SubscriberClass, class ThisType, class... RemainingTypes>
struct StatusUpdaterOverride<Self, SubscriberClass, ThisType, RemainingTypes...> : StatusUpdaterOverride<Self, SubscriberClass, RemainingTypes...>
{
  void handleService(ThisType const& service) override
  {
    static_cast<Self*>(this)->m_statusUpdater.updateService(service);
  }
  using StatusUpdaterOverride<Self, SubscriberClass, RemainingTypes...>::handleService;
};


template <class Self, class SubscriberClass, class ThisType>
struct StatusUpdaterOverride<Self, SubscriberClass, ThisType> : SubscriberClass
{
  void handleService(ThisType const& service) override
  {
    static_cast<Self*>(this)->m_statusUpdater.updateService(service);
  }
};


template <class StatusUpdatePolicy, class... ServiceType>
struct StatusUpdater : StatusUpdaterOverride<StatusUpdater<StatusUpdatePolicy, ServiceType...>, Subscriber<ServiceType...>, ServiceType...>
{
    StatusUpdater(StatusUpdatePolicy const& statusUpdater)
    : m_statusUpdater{statusUpdater}
    {}

    StatusUpdatePolicy m_statusUpdater;
};

[Live example]

答案 1 :(得分:2)

我看不到完全按照您想要的方式解决的方法。但是,您完全不需要virtual即可实现相同的行为。我最初像@Angew的答案一样考虑CRTP解决方案,然后想到了另一种可能性:

您可以像这样编辑Subscriber类:

template <typename ServiceType>
class Subscriber {
public:
    template <typename Handler>
    void handleService(ServiceType const& service, Handler&& hdler) {
        // Maybe give `updateService` a broader name that can extend to other service handlers
        std::forward<Handler>(hdler).updateService(service);
    }
};

这样,您的客户代码将变为:

template <typename StatusUpdatePolicy, typename... ServiceType>
struct StatusUpdater : Subscriber<ServiceType>...
{
    StatusUpdater(StatusUpdatePolicy const& statusUpdater)
    : m_statusUpdater{statusUpdater}
    {}
    template <typename ServiceT>
    void handleService(ServiceT const& service) override {
        Subscriber<ServiceT>::handleService(service, m_statusUpdater);
    }

    StatusUpdatePolicy m_statusUpdater;
}; 
相关问题