Jump to content
  • Advertisement
Sign in to follow this  
SyncViews

C++ Using templates to create a function wrapper/adapter to bind dynamic languages

This topic is 714 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am working on creating some C++ templates to ease bind functions and member functions to a dynamic system (Lua/Python/console/CLI/etc.), avoiding large numbers of hand coded wrappers / specs.

 

In the past I have either just gone with doing it by hand, or some sort of code gen. Which always seems to end up being a pain, since I still had a separate "specification" file, and it added build requirements like having a recent version of Ruby/Python/whatever+libs and poor/nonexistent IDE support.

 

So want to see if its possible in pure C++ now with variadic templates.

 

e.g. in the simple case of just dealing with strings (e.g. for a command console), to be able to do something such as this:

typedef std::vector<std::string> Args;

std::string to_string(float x); //plus normal and custom overloads
template<class T> T from_string(const std::string &str); //with specialisations

float add(float a, float b);
float mul(float a, float b);
void kill(Entity *entity);

FunctionTable functions = {
  {"add", &add},
  {"mul", &mul},
  {"kill", &kill}
};



I came up with a solution to have a template function that can call another function pointer type, although that results in me storing both pointers, and for member function pointers I cant safely cast them to/from void*/anything, so ended up using memcpy.

 

I understand that it is possible to pass a function pointer, member function pointer, or member variable pointer directly as a template argument, thus becoming part of the template itself. But can this be made to work with a pointer of unknown type? It seemed the template had to declare each component explicitly, e.g.:

  template<MyReturn (MyClass::*Func)(int, float)> Method wrapper();
  wrapper<&McClass::foo>(); //OK, but not generic
  
  template<typename Func> Method wrapper();
  wrapper<&McClass::foo>(); //invalid template argument for 'Func', type expected

Prototype code:

//This was only way I found to unpack each element of an array-like container into a normal function call
//Its just to give a parameter pack such as "0, 1, 2, 3" for a 4-arg function
template<size_t...> struct Indices {};
template<size_t N, size_t... Is> struct BuildIndices
    : BuildIndices<N - 1, N - 1, Is...> {};
template<size_t... Is> struct BuildIndices<0, Is...> : Indices<Is...> {};

template<class... Args, class Func, size_t ...indices>
std::string do_call_inner(Func func, const std::vector<std::string> &args, Indices<indices...>)
{
    //call by unpacking args and converting each from a from_string specialisation
    return to_string(func(from_string<Args>(args[indices])...));
}
//Another wrapper to add in BuildIndices, since needed Args separated in the function signature
template<class RetType, class ...Args>
std::string do_call(RetType(*func)(Args...), const std::vector<std::string> &args)
{
    if (args.size() != sizeof...(Args)) throw std::runtime_error("Invalid argument count");
    return do_call_inner<Args...>(func, args, BuildIndices<sizeof...(Args)>{});
}
template<class Func>
std::string wrapped_call(void *storage, const std::vector<std::string> &args)
{
    return do_call((Func)storage, args);
}

struct Method
{
    template<class Func> Method(Func f) : storage(f), caller(&wrapped_call<decltype(f)>) {}
    std::string operator ()(const std::vector<std::string> &args)const
    {
        return caller(storage, args);
    }
    void *storage;
    Caller caller;
};

And of course overloaded functions wont work with this approach. But is there any reasonable solution for that? I am thinking ill just carry on hand-coding the overload resolution for those.

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!