Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic datastructure with overloaded methods

I have a system with a number of message types that can be published/subscribed. When a new type is added, a large number of files have to be updated to add support for the new method type.

Is it possible to declare a C++ class with overloaded pure virtual methods as a variadic data structure?

When the C++ program below is compiled, the declaration of the 2nd publish method for type "MessageB" is hidden by the declaration of "MessageA".

main.cpp:57:41: error: no matching function for call to ‘IPublisher::publish(MessageB)’ publisher->publish(MessageB{"world"});

This is consistent with both GCC and Clang, but Clang does emit the useful warning:

warning: 'IPublishOne::publish' hides overloaded virtual function [-Woverloaded-virtual] virtual void publish(const T& message) = 0;

Why would method hiding occur since MessageA and MessageB are distinct types?

#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;
}
like image 292
Adam Crain Avatar asked Apr 18 '26 22:04

Adam Crain


1 Answers

Why would method hiding occur since MessageA and MessageB are distinct types?

You lack the final overrider.

IPublishOne<T, Ts...>::publish overrides IPublishOne<T>::publish as per class.virtual/2:

If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) as Base​::​vf is declared, then Derived​::​vf is also virtual (whether or not it is so declared) and it overrides Base​::​vf.

What you need is a final overrider:

Specify the final overrider in 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;
};
like image 55
Joseph D. Avatar answered Apr 21 '26 15:04

Joseph D.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!