Search code examples
c++std-functionstdbind

C++ std::function bind from derived class


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_)
{}

Solution

  • 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.