Clean implementation of function template taking f

2019-02-20 02:25发布

问题:

I've managed to implement and test my function wrapper implementation, however, the interface isn't as nice as it should be:

template < typename F, F* f >
void register_function( const char* name )
{
    int (*lf) (lua_State *) = function_wrapper< F, f >;
    register_native_function( lf, name );
}

While this works as expected, the usage requires to explicit template parameters:

register_function< decltype(hello), &hello >( "hello" );

Obviously the first parameter could be deduced from the first one, so ideally I'd like to just have

register_function< &hello >( "hello" );

Is it possible? Is there a neater way to do it?


Update: Answering the question, why is the parameter templated instead of passed:

Many binders (including Lua ones, as this is particularly designed for Lua) pass functions by value:

register_function("hello", &hello);

This is indeed more readable, and from the interface side more easily implementable. But that also means that the adress of the function needs to be stored somewhere.

To bind a function to Lua we need it to have the following prototype:

int (*lua_CFunction) (lua_State *)

No other information is passed, hence this is the entry and information we get when a bound function is called from Lua.

If the binding is done at compile time, we can provide a separate function (by templates) in the code that will be executed from Lua, giving us comparable performance to hand-written bindings, especially if the compiler optimizes away the boilerplate code.

If the binding is done at runtime, then we cannot create new functions and need a global function that somehow knows what function should it dispatch the call to. Normally, we wouldn't be able to get the information at all, but existing compile-time Lua binders take advantage of Lua custom per-function userdata or closures to store the additional information needed to perform the execution. However, this has a significant performance hit compared to a hand-written binding, because of possible additional memory allocations and closure dispatching.

I've had problems with perfomance of the runtime version in a previous binding implementation (although a very stressed one) which ended up in rewriting the most stressed parts into hand-written bindings, and, considering that this time I plan to do the lua calls in a realtime rendering loop, I want to find a solution that will be closer to hand-written performance.

If we pass the function as a parameter, we obviously cannot create the function binding at compile time.

回答1:

I'm sorry Dave, you cannot do that.

There have been proposals put forward to have template types that are deduced from literal types later on in the template type list. Last I checked, it wasn't going to get into C++1y (aka C++14).

A macro could help until the language adds the feature:

#define REGFUNC( F ) decltype(F), (F)
register_function< REGFUNC(hello) >( "hello" );

There was also talk of adding "lambda to C function" support in C++ (being able to take a stateful lambda, and asking it to generate a C function that will call it using that state), but I don't know how that is progressing.