質問: Luaのグローバル変数にlua_setglobalなどの関数を使ってintやdoubleといった普通の変数をグローバル変数として登録する方法は分かったのですが、インスタンスをグローバル変数として登録する方法が分かりません。どうすればいいのでしょうか。よろしくお願いします。
回答: メタテーブルの知識はありますか? 大まかな流れとしては * `luaL_newmetatable`でメタテーブルを作成し、メタメソッドやメンバー関数などを登録する。 * `lua_newuserdata`でユーザーデータを作成し、確保されたメモリ上にインスタンスを構築する。 * `luaL_setmetatable`で作成したユーザーデータに対してメタテーブルを設定する。 例としてシンプルなメンバーを持つTestClassを登録するコード例を以下に示します(lambdaやautoなどC++11の機能を使用しています。) ``` class TestClass { public: int get(){return m;} void set(int v){m = v;} private: int m=0; }; lua_State *L = luaL_newstate(); luaL_openlibs(L); { //クラスメンバの関数定義 auto setf =  { TestClass* setget = static_cast(check_userdata(L, 1, "TestClass")); setget->set(lua_tonumber(L, 2)); return 0; }; auto getf =  { TestClass* setget = static_cast(check_userdata(L, 1, "TestClass")); lua_pushnumber(L, setget->get()); return 1; }; auto gcf =  { TestClass* setget = static_cast(check_userdata(L, 1, "TestClass")); setget->~TestClass(); return 0; }; //メタテーブルの生成 luaL_newmetatable(L, "TestClass"); luaL_Reg funcs[] = { { "__gc",gcf }, { 0 ,0 }, }; setfuncs(L, funcs); //メタテーブルの__indexへメンバ関数を登録したテーブルの設定 lua_newtable(L); luaL_Reg indexfuncs[] = { { "set",setf }, { "get",getf }, { 0 ,0 }, }; setfuncs(L, indexfuncs); lua_setfield(L, -2, "__index"); lua_pop(L,1); //インスタンスをluaのuserdataとして作成 void* ptr = lua_newuserdata(L, sizeof(TestClass)); new(ptr) TestClass(); setmetatable(L, "TestClass");//TestClassのメタテーブルをユーザーデータへ設定 lua_setglobal(L, "testinstance");//構築したuserdataをtestinstanceへ登録 //登録したインスタンスのメンバーをLua上で呼んでみる luaL_dostring(L, "testinstance:set(4)"); luaL_dostring(L, "assert(4 == testinstance:get())"); } lua_close(L); ``` 割と面倒でスタック操作を間違えやすいので、binding libraryを使用することをお勧めします。 http://lua-users.org/wiki/BindingCodeToLua 例えば私の作成しているbinding libraryですと、以下のように記述することで同じようなことが行えます。 ``` kaguya::State L; //クラスの登録 L["TestClass"].setClass(kaguya::UserdataMetatable() .addFunction("get", &TestClass::get) .addFunction("set", &TestClass::set) ); //インスタンスの登録 L["testinstance"] = TestClass(); //登録したインスタンスのメンバーをLua上で呼んでみる L.dostring(L, "testinstance:set(4)"); L.dostring(L, "assert(4 == testinstance:get())"); ```