LuaBridge
LuaBridge copied to clipboard
addStaticFunction with std::function or lambda
First of let me say LuaBridge is great, it has allowed me to zip through writing my binding code at an incredible pace, thanks!
With that out of the way, I'm still stuck with a minor annoyance that seems to unnecessarily complicate binding static class methods.
When adding a regular class method, I can use an std::function that takes a lambda like this:
.beginClass<Lua::Value>("Value")
.addFunction("isSet", std::function<bool (const Lua::Value *)>([](const Lua::Value *v) { return v->value.isSet(); }))
.addFunction("isNone", std::function<bool (const Lua::Value *)>([](const Lua::Value *v) { return v->value.isNone(); }))
.endClass()
This is great, because it allows me to do simple type transformations without having to introduce helper functions or functor structs for each of them.
I want to do the same for static methods, like this (please disregard the usefulness of this in spite of a regular constructor, this is just to illustrate the kind of binding code I would like to be able to write)
.beginClass<Lua::Value>
.addStaticFunction("fromBoolean", std::function<Lua::Value (bool)>([](bool b) -> Lua::Value { return Lua::Value(b); }))
.endClass()
But unfortunately this doesn't compile because of an invalid cast.
/home/wouter/tmp/LuaBridge/Source/LuaBridge/detail/Namespace.h:508:33: error: invalid cast from type 'const std::function<Lua::Value (bool)>' to type 'void*'
I've tried all kinds of things like adding explicit casts and whatnot, but nothing works. I can make it work by just defining the code in the lambda as a static function in the source file, but I don't really like doing that as it separates the conversion logic from the binding code.
Is there a reason this use case is not supported, and/or is there a workaround?
Thanks, Wouter
Most probably nobody asked for this feature (and I personally don't use static class functions so much). The feature, of course, makes sense, for consistency and for more convenience. I can implement it, but it requires some time. Or you can contribute if you wish. Workaround is the classic approach - writing proxy functions.
Workaround is the classic approach - writing proxy functions.
That's what I did now, it works, but I like the in-line syntax that works for addFunction and addProperty better ;-)
I can implement it, but it requires some time. Or you can contribute if you wish.
I will consider trying to fix this myself and submit a PR for it, but I cannot afford to spend time on this at this very moment because of deadlines I need to meet. Maybe in a few weeks I could have a go at this.
-Wouter
#232
This is implemented here https://github.com/kunitoki/LuaBridge/commit/724d20669bc642e94ca268184a0aee57d67d649f#diff-ee96717b11ce812dcd9a3948fee2d0917c28655cdc7e4ee3a124a9a709c65cfbR51 for global functions and class methods in order to have the ability to pass lambdas with capture, will soon do also for static methods. once that is done i'll go shaving the current support for std::function which can be completely hidden in the implementation (don't need to be an overload) by using the current generic invocable from c++17.
In reality if you use non capturing lambdas, you don't need a std::function overload at all:
.beginClass<Lua::Value>("Value")
.addFunction("isSet", std::function<bool (const Lua::Value *)>([](const Lua::Value *v) { return v->value.isSet(); }))
.addFunction("isNone", std::function<bool (const Lua::Value *)>([](const Lua::Value *v) { return v->value.isNone(); }))
.endClass()
can be rewritten as
.beginClass<Lua::Value>("Value")
.addFunction("isSet", +[](const Lua::Value *v) -> bool { return v->value.isSet(); })
.addFunction("isNone", +[](const Lua::Value *v) -> bool { return v->value.isNone(); })
.endClass()
so those lambdas can be converted to a function pointer directly and be constructed with the addFunction taking a function pointer. of course adding a capture forces you to assign the lambda in a std::function.
but in 3.0 you can do this without problems:
int x = 100;
.beginClass<Lua::Value>("Value")
.addFunction("isSet", [x](const Lua::Value *v) -> bool { return x > 100 ? v->value.isSet() : false; })
.addFunction("isNone", [x](const Lua::Value *v) -> bool { return x < 100 ? v->value.isNone() : true; })
.endClass()
enjoy !