2

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.

Kornel Kisielewicz
  • 55,802
  • 15
  • 111
  • 149
  • Even if the first parameter can obviously "be deduced from the first one", I'd doubt that you can deduce the first from the second one. – nikolas Sep 09 '13 at 14:59
  • Yeah, but I only want to simplify one parameter :). – Kornel Kisielewicz Sep 09 '13 at 15:36
  • What would be the problem with `register_function("hello", &hello);` (i.e. why do you want to make this a template argument in the first place?) – David Rodríguez - dribeas Sep 09 '13 at 16:27
  • @KornelKisielewicz: I don't see any additional information being bound in the code in the question, just trying to figure out the real problem to solve and whether there is a better approach. As you have already noticed a template non-type argument is not in a deducible context and thus it's type must be known (in your case passed as a first argument) but depending on the exact real problem, there might be alternatives that are not much worse performing than the manual binding you mention – David Rodríguez - dribeas Sep 09 '13 at 16:51
  • The problem is that if not doing this at runtime we need a way to store that function pointer and retrieve it later when called, based only on the information available from the prototype. Possibly avoiding any singleton entities and compatible with the coroutine multi-threading of Lua. – Kornel Kisielewicz Sep 09 '13 at 16:55

2 Answers2

3

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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • The bit on deduced types is interesting, is there a proposal document for it? And yeah, a macro would cut down the typing a bit, but macros are so evil :(. – Kornel Kisielewicz Sep 09 '13 at 21:28
  • @KornelKisielewicz I don't recall where exactly I'd seen it: basically, it was allowing a `template` class's name to be used as a constructor, and the type of the `template` class being deduced from it. Ie, automated `make_foo( t )` so you can just `foo(t)`. Probably when reading through some collection of proposals for C++1y. – Yakk - Adam Nevraumont Sep 09 '13 at 21:33
  • @Yakk, good answer and tips. Is there any reason why `decltype(&F)` can't be used in the template? That way the type would not need to be deduced. However I can't get it to work at http://stackoverflow.com/questions/33435553/how-to-fix-error-refactoring-decltype-inside-template (in which I reference your answer). – Sam Liddicott Oct 30 '15 at 13:09
0

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>("?!").)

Davis Herring
  • 36,443
  • 4
  • 48
  • 76