1

I would like to use polymorphism to have a vector of std::function<void(Base&)> that take in a base class as a parameter, and fill the vector with std::function with a similar signature that instead take in a derived class as a parameter.

#include <functional>
#include <vector>
#include <stdio.h>

class Base
{
public:
    virtual ~Base() = default;
};

class Derived : public Base
{
public:
    Derived(int x, int y) : a(x), b(y) {}
    int a, b;
};

void DerivedFunction(Derived& d)
{
    printf("A: %d, B: %d\n", d.a, d.b);
}

using FunctionSignature = std::function<void(Base&)>; // Changing Base& to Derived& compiles fine.
static std::vector<FunctionSignature> myVector;

int main()
{
    FunctionSignature fn = [](Derived& d){ printf("A: %d, B: %d\n", d.a, d.b); };
    
    myVector.push_back(fn); // error
    myVector.push_back(std::forward<FunctionSignature>(fn)); // error
    myVector.push_back(std::bind(&DerivedFunction, std::placeholders::_1)); // error
    return 0;
}

What would be the correct way to push_back DerivedFunction into the vector?

Godbolt link: https://godbolt.org/z/b6Taqoqs8

avilapa
  • 11
  • 3

1 Answers1

1

A Derived& can be implicitly converted to a Base&. Inheritance models a is-a relation: Every Derived instance is-a Base. This relation is not mutual. You cannot implicitly convert a Base& to a Derived& (not every Base is-a Derived).

You can use a dynamic_cast. It will throw an exception when the dynamic type of the object is not Derived:

template <typename F>
auto wrap(F f) {
    return [f](Base& b) { 
        f(dynamic_cast<Derived&>(b));
    };
}

int main() {
    FunctionSignature fn = wrap([](Derived& d){ printf("A: %d, B: %d\n", d.a, d.b); });
}

Live Demo

You could catch the exception in the wrapper, or cast between pointers to get a nullptr rather than an exception (for details see here).

As mentioned in a comment, the vector is a distraction. If the first line in main is fixed you can use the same with the vector.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185