简体   繁体   中英

Dynamic C++ Function Parameters

This is quite possibly the wrong title, but I don't know how else to describe it. What I'm trying to do is call a C++ function from my scripting language (running in a VM). I've run into some trouble figuring out how to pass in parameters to the function.

My best solution so far is to do this:

void func(int a) {

// Start param copy
char c;
char* par_start = &c - sizeof(char) - getCurrentFuncParamOffset();
copyCurrentParams(par_start);
// End copy

// Code

}

Then, to call the function I first expose it to the VM, giving the parameters to it. This is some shortened code, but everything is cast to a void(*) so it can be stored in a hash table.

EXPOSE(test, int);
vm.call("test", 12)

EXPOSE grabs a pointer to the function test, and stores that it requires a single into to be called. It stores the pointer as a void(*)() in a hash table so that when I want to call it, I can make a call from the VM and it is resolved. Then the code inside of the function (which I have expanded from a macro in the question) will copy the parameters that were passed in from the call to the VM to the parameters of the function.

This works but it is not the most elegant solution, especially because I'll have to call a macro for each function that I want to be exposed for scripting. Is there a better solution? Thanks.

You can just as well use what C++ has to offer. Here's a little example I threw together.

class ScriptObj {}; // Your type that encapsulates script objects. 
                    // May be as simple as an integer or a string,
                    // or arbitrarily complex like PyObj

template <typename T> T from_script(ScriptObj); // conversion to and from
template <typename T> ScriptObj to_script(T);   // C++ types. You provide
                                                // specialized implementations.
                                                // Bad conversions should throw.

// Abstract base class for C++ functions callable from the scripts.
// The scripting engine should pass a vector of parameters and a pointer to result.
struct script2cxx
{
    virtual ~script2cxx() {}
    virtual ScriptObj operator()(const std::vector<ScriptObj>& params) = 0;
};    


// Concrete class that exposes a C++ function to the script engine.
template <class Res, class ... Param>
struct script2cxx_impl : script2cxx
{

    using funcType = Res(*)(Param...);

    virtual ScriptObj operator()(const std::vector<ScriptObj>& params)
    {
        if (sizeof...(Param) != params.size())
            throw std::domain_error("Invalid size of parameter array");
        return to_script<Res>(call_impl<std::tuple<Param...>>(func, params, std::make_index_sequence<sizeof...(Param)>()));
    }

    template <class Tuple, std::size_t... N>
        Res call_impl(funcType func, const std::vector<ScriptObj>& params, std::index_sequence<N...>)
        {
            return func(from_script<typename std::tuple_element<N, Tuple>::type>(params[N])...);
        };

    funcType func;

    script2cxx_impl(funcType func) : func(func) {}
};

// a helper biold function
template  <class Res, class ... Param>
auto expose(Res(*func)(Param...)) {
    return new script2cxx_impl<Res, Param...>(func);
}

Now you can build a map of script2cxx (smart) pointers and call them with vectors of your script objects.

 std::map<std::string, std::unique_ptr<script2cxx>> exposed;


 int foo(double, char[], int**) {...}

 // below is the only line you need to add
 // if you want to expose any standalone C++ function.
 // no boilerplate.

 exposed["foo"]=expose(foo); // you can wrap this in a macro if you want

And call them:

 std::vector<ScriptObj> somevector = ...;
 std::string somestring = ...;
 (*exposed[somestring])(somevector); 

No unsafe casts and/or void pointers were harmed in making this example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM