Create function call dynamically in C++

Yes we can. No FFI library needed, no restriction to C calls, only pure C++11.

#include <iostream>
#include <list>
#include <iostream>
#include <boost/any.hpp>

template <typename T>
auto fetch_back(T& t) -> typename std::remove_reference<decltype(t.back())>::type
{
    typename std::remove_reference<decltype(t.back())>::type ret = t.back();
    t.pop_back();
    return ret;
}

template <typename X>
struct any_ref_cast
{
    X do_cast(boost::any y)
    {
        return boost::any_cast<X>(y);
    }
};

template <typename X>
struct any_ref_cast<X&>
{
    X& do_cast(boost::any y)
    {
        std::reference_wrapper<X> ref = boost::any_cast<std::reference_wrapper<X>>(y);
        return ref.get();
    }
};

template <typename X>
struct any_ref_cast<const X&>
{
    const X& do_cast(boost::any y)
    {
        std::reference_wrapper<const X> ref = boost::any_cast<std::reference_wrapper<const X>>(y);
        return ref.get();
    }
};

template <typename Ret, typename...Arg>
Ret call (Ret (*func)(Arg...), std::list<boost::any> args)
{
    if (sizeof...(Arg) != args.size())
        throw "Argument number mismatch!";

    return func(any_ref_cast<Arg>().do_cast(fetch_back(args))...);
}

int foo(int x, double y, const std::string& z, std::string& w)
{
    std::cout << "foo called : " << x << " " << y << " " << z << " " << w << std::endl;
    return 42;
}

Test drive:

int main ()
{
    std::list<boost::any> args;
    args.push_back(1);
    args.push_back(4.56);
    const std::string yyy("abc");
    std::string zzz("123");
    args.push_back(std::cref(yyy));
    args.push_back(std::ref(zzz));
    call(foo, args);
}

Exercise for the reader: implement registerNativeFunction in three easy steps.

  1. Create an abstract base class with a pure call method that accepts a list of boost::any, call it AbstractFunction
  2. Create a variadic class template that inherits AbstractFunction and adds a pointer to a concrete-type function (or std::function). Implement call in terms of that function.
  3. Create an map<string, AbstractFunction*> (use smart pointers actually).

Drawback: totally cannot call variadic C-style functions (e.g. printf and friends) with this method. There is also no support for implicit argument conversions. If you pass an int to a function that requires a double, it will throw an exception (which is slightly better than a core dump you can get with a dynamic solution). It is possible to partially solve this for a finite fixed set of conversions by specializing any_ref_cast.