Good question. I had some vague idea of how luabind does what it does, but I did not know enough to answer fully and accurately. Armed with an IDE and a debugger, I began to cut through the following very simple part:
struct C { int i; int f(int x, const char* s) }; lua_State* L = luaL_newstate(); open(L); module(L) [ class_<C>("C") .def_readwrite("index", &C::i) .def("f", &C::f) ];
First of all, it should be noted that L is passed to luabind a lot, the open call creates several global characters in the Lua state: __luabind_classes type userdata and two functions class and property . Luabind does not seem to use global variables - everything it needs is stored in the lua environment.
Now we move on to module(L)[...] . The source code is the best explanation, first here is module :
inline module_ module(lua_State* L, char const* name = 0) { return module_(L, name); }
Simple enough, here is module_ :
class LUABIND_API module_ { public: module_(lua_State* L_, char const* name); void operator[](scope s); private: lua_State* m_state; char const* m_name; };
So our little program does this call statement [] in the module_ class with some definitions (the scope parameter), but the module_ class knows in what mode Lua works. The scope class is also interesting for viewing (some parts are omitted and some are slightly simplified):
struct LUABIND_API scope {
scope creates a linked list of nodes detail::registration , this list is based on the use of operator, Therefore, when one module(L) [class_<...>..., class_<...>...] , class_ , which inherits from scope , initializes its base with an instance of detail::registration , then the scope comma operator builds a linked list of all registrations, it is passed to module_::operator[] which calls scope::register_ , which, in turn, enumerates the chain and calls register_ for all these detail::registration objects. lua_State always passed to register_ .
Phew Now let's see what happens if you do class_<C>("C").def("f", &C::f) . This creates an instance of class_<C> with a specific name, which is included in the detail::registration member in class_ . The class_::def method call is written to a regressive structure and something else, but here a very interesting line is deeper in the def call chain:
object fn = make_function( L, f, deduce_signature(f, (Class*)0), policies);
Oooh, deduce_signature , I really wanted to see this. Now I want to abandon it, but the way it works is this: through dark preprocessing witchcraft using boost ( BOOST_PP_ITERATE and some other utilities) for each N between the one and LUABIND_MAX_ARITY the following is created:
template <class R, class T, class A1, classA2, ..., classAN> boost::mpl::vectorN_PLUS_2<R, T, A1, A2, ..., AN> // type of return value deduce_signature(R(T::*)(A1, A2, ..., AN)) { return boost::mpl::vectorN_PLUS_2<R, T, A1, A2, ..., AN>() }
Again, such a function is generated for all N between 1 and LUABIND_MAX_ARITY, which by default is 10. There are a couple of overloads for processing const methods, virtual wrappers and free functions, etc., which means that there are about 50 deduce_signature functions that get to your sources right after the preprocessor and before starting compilation. From there, the task of the compiler is to choose the correct deduce_signature overload for the functions you pass to def , and this will return the correct boost::mpl::vectorX type. From there, make_function can do something - it has a list of parameter types [compilation time], and after some template magic they are counted, converted to and from Lua values, and so on.
I will stay here. The study is based on Luabind 0.8.1. Feel free to browse / debug the Luabind code for additional answers - it takes some time, but it is not so difficult after you get used to the style :) Good luck.
TL DR: Magic ... black magic