c++functionlambdareturn-typevariant

How to deduce return type of each function (on derived class) stored in a container


I would like to get return type of each function stored in a container. I have tried std::any and std::variant but i couldn't figure this out. Details below:

#include <random>
#include <vector>
#include <functional>
using namespace std;

class Base
{
public: virtual void test() { }
};

class Derived1 : public Base
{
public: virtual void test() { }
};

class Derived2 : public Base
{
public: virtual void test() { }
};

int main ()
{
    std::vector<std::function < Base(void)>> b;

    b.push_back([&]() { return Derived1(); });
    b.push_back([&]() { return Derived2(); });
    b.push_back([&]() { return Base(); });

    std::shuffle(b.begin(), b.end(), std::default_random_engine {});

    for (auto fn : b)
    {
        // Here I would like to reach the derived classes from "fn" somehow and use it like "new Derived1"
        //decltype(fn)::result_type ----------> this gives me Base only but i want the derived as well
    }

}

Solution

  • I have managed to solve this two different ways.

    First way:

    int main()
    {
        std::vector<std::function<Base& ()>> b;
    
        b.push_back([]() -> Base& { static Derived1 d1; return d1; });
        b.push_back([]() -> Base& { static Derived2 d2; return d2; });
        b.push_back([]() -> Base& { static Base b; return b; });
    
        std::shuffle(b.begin(), b.end(), std::default_random_engine{});
    
        for (auto& fn : b)
        {
            if (auto derived1_ptr = dynamic_cast<Derived1*>(&fn()))
            {
                derived1_ptr->test();
                Derived1* var = new Derived1(*derived1_ptr);
                var->test();
            }
            else if (auto derived2_ptr = dynamic_cast<Derived2*>(&fn()))
            {
                derived2_ptr->test();
                Derived2* var = new Derived2(*derived2_ptr);
                var->test();
            }
        }
    
        return 0;
    }
    

    Second way:

    int main()
    {
        std::vector<std::function<std::shared_ptr<Base>()>> b;
    
        b.push_back([&]() { return std::make_shared<Derived1>(); });
        b.push_back([&]() { return std::make_shared<Derived2>(); });
        b.push_back([&]() { return std::make_shared<Base>(); });
    
        std::shuffle(b.begin(), b.end(), std::default_random_engine{});
    
        for (auto fn : b)
        {
            if (auto derived1_ptr = std::dynamic_pointer_cast<Derived1>(fn()))
            {
                derived1_ptr->test();
                shared_ptr<Derived1> var = std::make_shared<Derived1>(*derived1_ptr);
                var->test();
            }
            else if (auto derived2_ptr = std::dynamic_pointer_cast<Derived2>(fn()))
            {
                derived2_ptr->test();
                shared_ptr<Derived2> var = std::make_shared<Derived2>(*derived2_ptr);
                var->test();
            }
        }
    
        return 0;
    }