3

If I had a base class MessageWrapper, with a child class SetConfigurationData, why does binding with a child class parameter not work?

Shouldn't it work polymorphically?

Class MessageHandler
{
    public:
    void RegisterHandler(std::function<void(MessageWrapper &)> callback_)
    {}
};

class Testing
{
    public:

    Testing(MessageHandler &handler_)
        : m_Handler(handler_)
    {
        m_Handler.RegisterHandler(std::bind(&Testing::TestMessageHandler, this, std::placeholders::_1));
    }

    void TestMessageHandler(SetConfigurationData &msg_)
    {}

    MessageHandler m_Handler;
};

I get the error: "Failed to specialize function template 'unkown-type std::invoke(Callable &&, Types &&..)'

It works if I do this:

void TestMessageHandler(MessageWrapper &msg_)
{}
user2654735
  • 323
  • 5
  • 19
  • Title nitpick: you're not binding *from* a derived class, you're trying to bind a covariant function. – cdhowie Dec 22 '17 at 03:46

1 Answers1

2

Polymorphism cannot work like this. I will explain with an example. Let's say the function.

void TestMessageHandler(SetConfigurationData &msg_)

has something specific to the child object in it's body. Say

msg.child_method()

Now since RegisterHandler callback_() takes base class as argument, what should it do with this "msg.child_method()" call since it's not a base class method ?

Now, what happens if we do it the other way round. The following works.

class MessageWrapper
{
};

class SetConfigurationData : public MessageWrapper
{
    public:
    void RegisterHandler(std::function<void(SetConfigurationData&)> callback_)
    {}
};

class MessageHandler
{
};

class Testing
{
    public:

        Testing(SetConfigurationData &handler_)
            : m_Handler(handler_)
        {
            m_Handler.RegisterHandler(std::bind(&Testing::TestMessageHandler, this, std::placeholders::_1));
        }

        void TestMessageHandler(MessageWrapper &msg_)
        {}

        SetConfigurationData m_Handler;
};

Even though TestMessageHandler takes MessageWrapper as argument, u can bind it to callback_ which takes Child class (SetConfigurationData) as argument.

Santosh
  • 59
  • 2
  • This answer is so close to clearly explaining the situation, but it's missing a very important detail: that the caller can invoke the function with a reference to a `MessageWrapper` which isn't a `SetConfigurationData`. E.g. `class OtherMessage : public MessageWrapper {}; OtherMessage foo; callback_(foo);` -- This satisfies the contract of the `MessageWrapper&` argument type, but does not satisfy `SetConfigurationData&`, which is why the covariant function conversion is disallowed. – cdhowie Dec 22 '17 at 16:18