Binding luabind::object to a boost::function
Reko Tiira <[email protected]>
| Newsgroups | gmane.comp.lang.lua.bind.user |
|---|---|
| Message-ID | <[email protected]> |
Hey,
I've been implementing lua as a scripting language on top of set of classes,
which I want to be able to be used from lua.
Everything is working good so far, and luabind has made my job a lot easier
than I thought. Now I want to do something like this.. I have a set of
functions that register event callbacks in my class, the callbacks are
simply instances of boost::function. I want to be able to transparently bind
a function from lua into a boost::function so that I can register lua
functions as callbacks.
I noticed that luabind::object has overloads for operator() so it can call a
lua function directly, so I attempted this first:
// obj is a luabind::object
boost::function<void (int)> func = obj;
func(100);
This works very well, and I thought that this is going to be easier than I
thought. However the first issue was apparent when I tried to add a return
value:
boost::function<int (int)> func = obj;
int res = func(100);
Now this doesn't work anymore. I noticed that the reason is because the
proxy object that operator() returns, will return another luabind::object as
a result, instead of the actual C++ datatype. To make sure I understood what
I was seeing correctly, I attempted the following:
boost::function<luabind::object (int)> func = obj;
int n = luabind::object_cast<int>(func(50));
This indeed worked and gave the expected result. However the problem is that
for this to work I'd have to go back to the existing classes and change the
callbacks to return luabind::object instead, which would break existing
code. Additionally I want lua to just be an additional component, the
classes should still be available to be used directly from C++, and I
definitely don't want to maintain two lists of callbacks (one for C++, one
for lua). I absolutely want to get this done transparently to the original
class.
Next thing I noticed was that luabind::call_function lets me automatically
convert the return value to the type I want, like this:
int n = luabind::call_function<int>(obj, 100);
So I attempted to get this bound to boost::function next. With some
boost::bind magic I should be able to make this work. My first attempt was
one without passing parameters like this:
boost::function<int ()> func = boost::bind(&luabind::call_function<int>,
obj);
int n = func();
This indeed worked as intended, but next I wanted to add passing parameters
to the callback. I tried:
boost::function<int (int)> func = boost::bind(&luabind::call_function<int>,
obj, _1);
int n = func(100);
However things didn't go so smoothly, I got the following error:
error C2664: 'luabind::detail::proxy_function_caller<Ret,Tuple> (lua_State
*,const char *)' : cannot convert parameter 2 from 'int' to 'const char *'
Apparently it picked the wrong overload for luabind::call_function<int>.
Looking at the signature of call_function, I can see that it returns some
whacky detail function wrapper, that nobody right in their mind would want
to cast to by hand. So I attempted to resolve the issue with the new C++0x
decltype operator:
typedef decltype(luabind::call_function<int>(obj, int())) ret_type;
boost::function<int (int)> func = boost::bind((ret_type (*)(const
luabind::object&, const int&))&luabind::call_function<int>, obj, _1);
int n = func(100);
This indeed works well! However I'm not very satisfied with this solution
because first of all it requires decltype operator to work, and nobody wants
to write the actual return type of the expression by hand. It also feels a
bit too difficult way to do it. There must be a better way, seeing how
luabind already provides two different facilities:
1) luabind::object operator() that can pass arguments to boost::function
just fine but can't deal with return type transparently.
2) luabind::call_function that can return the value just fine, but can't
deal with the parameters due to boost::bind not being able to deduce the
correct overload automatically.
My question is that is there any better way to do it that is already
supported by luabind. I did come up with a solution that worked for me, but
I really think it should be part of luabind core, instead of having to do
this myself. What I did in the end was something like this:
template <typename T> struct function { function(const luabind::object& obj)
: m_func(obj) { if (luabind::type(obj) != LUA_TFUNCTION) { throw
std::invalid_argument("invalid lua object"); } } T operator()() { return
luabind::call_function<T>(m_func); } template <typename A1> T
operator()(const A1& a) { return luabind::call_function<T>(m_func, a); }
// ... bunch of more overloads for operator() private: luabind::object
m_func; };
Now I can just do:
boost::function<int (int)> func = function<int>(obj); int n = func(100);
Hence I have a nice and clean solution for transparently binding lua
functions in C++ to existing callback mechanisms.
If this is not possible out of the box in luabind, I strongly suggest it to
be added, as I'd think it is something many lua embedders tackle with and
would appreciate. I understand the need of luabind::object operator()
returning luabind::object since you have to be able to deal with values that
are not convertible to C++, hence it'd be awesome to have something like
luabind::function to provide this extra functionality to luabind::object,
without having to do insane casts for overload resolution on
luabind::call_function.
On an unrelated note, can someone explain to me why luabind::object's
operator() is not callable on const objects? For example:
void foo(const luabind::object& obj)
{
luabind::call_function<void>(obj); // works
obj(); // doesn't
}
For the later to work you have to pass by luabind::object. I know it's cheap
to copy these objects since all they do is hold a reference to lua's
registry, but I'm still curious
Regards,
Reko Tiira
------------------------------------------------------------------------------
Achieve unprecedented app performance and reliability
What every C/C++ and Fortran developer should know.
Learn how Intel has extended the reach of its next-generation tools
to help boost performance applications - inlcuding clusters.
http://p.sf.net/sfu/intel-dev2devmay
_______________________________________________
luabind-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/luabind-user