Kornel Kisielewicz
Kornel Kisielewicz

Reputation: 57555

Clean implementation of function template taking function pointer

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.

Upvotes: 2

Views: 268

Answers (2)

Davis Herring
Davis Herring

Reputation: 39818

Adding the six years of this question’s age to the tagged language version: C++17 allows template parameters to be declared with placeholders.

template < auto &F >
void register_function( const char* name )
{
    int (*lf) (lua_State *) = function_wrapper< std::remove_reference_t<decltype(F)>, F >;
    register_native_function( lf, name );
}

This is particularly useful with functions, since the conceptual type “callable” is really many C++ types. (Using a reference helps avoid silly things like register_function<2>("?!").)

Upvotes: 0

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275395

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.

Upvotes: 3

Related Questions