How to store functional objects with different signatures in modern C ++

advertisements

I would like to know if there is a way to store functional objects (functions, callbacks, ...) with different signatures in a standard container (std::map) with modern C++ only. The library that manages the container does not know which signatures will be used by its "clients".

My need is the same as exposed here : How to store functional objects with different signatures in a container?, and this solution https://stackoverflow.com/a/8304873/4042960 is about perfect for me: I would just like to do the same thing without boost. As far as I know, there is no std::any. The best solution for me would be to store std::function without specialized them, but I do not know how to do it, if it is possible.

Edit:

With the answers you give to me I wrote this example :

#include <map>
#include <memory>
#include <functional>
#include <string>
#include <iostream>
#include <stdexcept>

class FunctionMap
{
    struct Base {
        virtual ~Base() {}
    };

    template<class R, class... Args>
    struct Func : Base
    {
        std::function<R(Args...)> f;
    };

    std::map<std::string, std::shared_ptr<Base> > _map;

public:

    template<class R, class... Args>
    void store(const std::string &key, const std::function<R(Args...)> &f) {
        auto pfunc = std::make_shared<Func<R, Args...> >();
        pfunc->f = f;
        _map.insert(std::make_pair(key, pfunc));
    }

    template<class R, class... Args>
    std::function<R(Args...)> get(const std::string &key) {
        auto pfunc = std::dynamic_pointer_cast<Func<R, Args...> >(_map[key]);
        if (pfunc)
            return pfunc->f;
        else
            throw std::runtime_error("Bad type for function's parameters");
    }
};

// test

int plus(int a, int b) { return a+b; }

double multiplies(double x, double y) { return x*y; }

int main()
{
    FunctionMap fm;

    fm.store("plus", std::function<int(int, int)>(&plus));
    fm.store("multiplies", std::function<double(double, double)>(&multiplies));
//    fm.store("square", std::bind(&multiplies, std::placeholders::_1, std::placeholders::_1));

    std::cout << "5 + 3 = " << fm.get<int, int, int>("plus")(5, 3) << std::endl;
    std::cout << "5 * 3 = " << fm.get<double, double, double>("multiplies")(5.0, 3.0) << std::endl;

    return 0;
}

This works well, but I would like to improve it a bit:

1) I would like to be able to use std::bind : fm.store("square", std::bind(&multiplies, std::placeholders::_1, std::placeholders::_1)); but currently that does not compile ;

2) I would like to use fm.get<int (int, int)>("plus") instead of fm.get<int, int, int>("plus") but I do not know how to do it.

Many thanks for your help !


You can write your own any. Without all the compiler workarounds and stuff, boost::any can be written in about 30 lines of code.