Do It Yourself Cpp Binding |
|
Here's a few tricks I've found, mostly in code form, which work together:
lauxlib has really, really useful functions for manipulating userdata metatables. Those are adequately covered in the [Lua Auxiliary Library] in the reference manual. I suggest giving each metatable a name identical to the classname; this will enable fun and evil preprocessor tricks like those that follow here. To those unfamiliar with the operator: the # operator in #define statements will cause the following argument to be placed in quotes when the macro is expanded.
A useful macro to simplify checking whether the object at a given stack position is of a given userdata type (registered with luaL_newmetatable):
#define lua_userdata_cast(L, pos, T) static_cast<T*>(luaL_checkudata((L), (pos), #T))
I use stuff like this a lot in my metamethods:
if(const MyClass* myclass = lua_userdata_cast(L, 1, MyClass)) { MyClass->SomeMethod(); return 0; }
Dig it:
void* operator new(size_t size, lua_State* L, const char* metatableName) { void* ptr = lua_newuserdata(L, size); luaL_getmetatable(L, metatableName); // assert(lua_istable(L, -1)) if you're paranoid lua_setmetatable(L, -2); return ptr; } #define lua_pushobject(L, T) new(L, #T) T
Now, instead of doing boxpointer weirdness, to push an object of a type whose metatable was created with luaL_newmetatable onto the stack, do like so:
lua_pushobject(L, MyClass)(arg1, arg2, arg3);
...thus allowing you to construct a new MyClass
directly into the memory region it'll be using!
watch this:
template<typename T> int GCMethod(lua_State* L) { static_cast<T*>(lua_touserdata(L, 1))->~T(); return 0; }
This templated method makes a perfect __gc method. Like so:
lua_pushstring(L, "__gc"); lua_pushcfunction(L, GCMethod<MyClass>); lua_settable(L, 1);