具有重载方法的可变参数数据结构

时间:2018-06-19 23:36:26

标签: c++ c++11 templates variadic-templates overloading

我的系统具有许多可以发布/订阅的消息类型。添加新类型时,必须更新大量文件以增加对新方法类型的支持。

是否可以将带有重载纯虚拟方法的C ++类声明为可变数据结构?

编译下面的C ++程序时,类型“ MessageB”的第二种发布方法的声明被“ MessageA”的声明隐藏。

  

main.cpp:57:41:错误:没有匹配的函数可以调用'IPublisher :: publish(MessageB)'Publisher-> publish(MessageB {“ world”});

这与GCC和Clang都一致,但是Clang确实会发出有用的警告:

  

警告:'IPublishOne :: publish'隐藏了重载的虚拟函数[-Woverloaded-virtual] virtual void publish(const T&message)= 0;

由于MessageA和MessageB是不同的类型,为什么会发生方法隐藏?

#include <iostream>
#include <memory>

using namespace std;

template <class...Ts>
struct IPublishOne;

template <class T>
struct IPublishOne<T>
{
    virtual void publish(const T& message) = 0;
};

template <class T, class... Ts>
struct IPublishOne<T, Ts...> : IPublishOne<Ts...>
{
    virtual void publish(const T& message) = 0;
};

struct MessageA
{
    std::string value;
};

struct MessageB
{
    std::string value;
};

struct IPublisher : public IPublishOne<MessageA, MessageB>
{
    virtual ~IPublisher() = default;
};

struct Publisher : public IPublisher
{

    void publish(const MessageA& message) override
    {
        std::cout << message.value << std::endl;
    }

    void publish(const MessageB& message) override
    {
        std::cout << message.value << std::endl;
    }
};

int main()
{
    const std::unique_ptr<IPublisher> publisher = std::make_unique<Publisher>();

    publisher->publish(MessageA{"hello"});

    // this produces compile error
    publisher->publish(MessageB{"world"});

    return 0;
}

2 个答案:

答案 0 :(得分:3)

  

为什么由于MessageA和MessageB不同而导致方法隐藏   类型?

您没有最终替代者

IPublishOne<T, Ts...>::publish 覆盖 IPublishOne<T>::publish,根据class.virtual/2

  

如果在vf和$ {1}中声明了 virtual 成员函数class Base。   class Derived,直接或间接源自成员Base   具有相同名称的函数vf,parameter-type-list,cv-qualification,   并声明与Base​::​vf相同的ref限定符,然后   Derived​::​vf也是 virtual (无论是否声明),并且   它会覆盖Base​::​vf

您需要的是final overrider

struct IPublishOne<T, Ts...>中指定最终替代程序

template <class T, class... Ts>
struct IPublishOne<T, Ts...> : IPublishOne<Ts...>
{
    using IPublishOne<Ts...>::publish;  // final overrider for
                                        // IPublishOne<T>::publish
    virtual void publish(const T& message) = 0;
};

答案 1 :(得分:1)

问题在于,在类中定义publish()方法会隐藏所有从基类继承的publish()方法。

您可以解决此问题,在using中添加IPublishOne

template <class T, class... Ts>
struct IPublishOne<T, Ts...> : IPublishOne<Ts...>
{
   using IPublishOne<Ts...>::publish;  // <<<-------------

    virtual void publish(const T& message) = 0;
};

使可见的继承publish()可见。