C++ std::function связывается из производного класса

Если бы у меня был базовый класс MessageWrapper с дочерним классом SetConfigurationData, почему привязка с параметром дочернего класса не работает?

Разве это не должно работать полиморфно?

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;
};

Я получаю сообщение об ошибке: "Не удалось специализировать шаблон функции "неизвестный тип std::invoke(Callable &&, Types &&..)"

Это работает, если я делаю это:

void TestMessageHandler(MessageWrapper &msg_)
{}

person user2654735    schedule 22.12.2017    source источник
comment
Придирка к заголовку: вы не привязываете из производного класса, вы пытаетесь привязать ковариантную функцию.   -  person cdhowie    schedule 22.12.2017


Ответы (1)


Полиморфизм не может так работать. Я объясню на примере. Скажем, функция.

void TestMessageHandler(SetConfigurationData &msg_)

имеет что-то специфичное для дочернего объекта в его теле. Сказать

msg.child_method()

Теперь, когда RegisterHandler callback_() принимает базовый класс в качестве аргумента, что ему делать с этим вызовом «msg.child_method()», поскольку это не метод базового класса?

Теперь, что произойдет, если мы сделаем это наоборот. Следующие работы.

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;
};

Несмотря на то, что TestMessageHandler принимает MessageWrapper в качестве аргумента, вы можете связать его с callback_, который принимает дочерний класс (SetConfigurationData) в качестве аргумента.

person Santosh    schedule 22.12.2017
comment
Этот ответ так близок к ясному объяснению ситуации, но в нем отсутствует очень важная деталь: вызывающая сторона может вызывать функцию со ссылкой на MessageWrapper, который не является SetConfigurationData. Например. class OtherMessage : public MessageWrapper {}; OtherMessage foo; callback_(foo); -- Это удовлетворяет контракту с типом аргумента MessageWrapper&, но не удовлетворяет SetConfigurationData&, поэтому преобразование ковариантной функции запрещено. - person cdhowie; 22.12.2017