This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <new> | |
class MyClass | |
{ | |
public: | |
MyClass() | |
{ | |
value = 0; | |
puts("MyClass::MyClass called"); | |
} | |
~MyClass() | |
{ | |
puts("MyClass::~MyClass called"); | |
} | |
int value; | |
}; | |
static const char* myClassName = "MyClass"; | |
#define GET_MYCLASS \ | |
MyClass* p = (MyClass*)luaL_checkudata(L, 1, myClassName); \ | |
if (!p) { return 0; } | |
static int MyClassNew(lua_State *L) | |
{ | |
MyClass* p = new (lua_newuserdata(L, sizeof(MyClass))) MyClass; | |
luaL_getmetatable(L, myClassName); | |
lua_setmetatable(L, -2); | |
return 1; | |
} | |
void BindMyClass() | |
{ | |
int r = luaL_newmetatable(L, myClassName); | |
assert(r); | |
lua_pushstring(L, "__index"); | |
lua_pushvalue(L, 1); | |
lua_settable(L, -3); | |
static struct luaL_Reg methods[] = | |
{ | |
{ "__gc", [](lua_State* L) { GET_MYCLASS p->~MyClass(); return 0; } }, | |
{ "SetValue", [](lua_State* L) { GET_MYCLASS p->value = (int)lua_tointeger(L, -1); return 0; } }, | |
{ "GetValue", [](lua_State* L) { GET_MYCLASS lua_pushinteger(L, p->value); return 1; } }, | |
{ nullptr, nullptr }, | |
}; | |
luaL_setfuncs(L, methods, 0); | |
lua_pop(L, 1); | |
lua_register(L, "MyClass", MyClassNew); | |
} |
また、placement newでMyClassのメモリ確保をluaに任せるようにします。これによってダブルポインタを使う無駄を省いた上にコードもすっきりしました。deleteのかわりにp->~MyClassを明示的に呼ぶ必要があります。placement newを使うためには #include <new>
単独のサンプルとしてはこのくらいが最短かと思いますが、複数のクラスをバインドするなら上のコードの一部を共通化できるのでもう少し短くなりそうです。例えばメタテーブルを生成して__indexに自身を指定するあたりはサブルーチン化します。
MyClassNewはマクロ化すれば複数クラスで使いまわせそうです。本当はテンプレート関数化したいところですが、メタテーブルに渡す文字列をテンプレート引数にするにはややトリックが必要です。現状のC++では文字列定数をテンプレート引数に出来ないためです。
No comments:
Post a Comment