回答編集履歴

2 binding libraryを使用した場合の例を追加

satoren

satoren score 99

2017/02/04 05:25  投稿

メタテーブルの知識はありますか?
大まかな流れとしては
* ``luaL_newmetatable``でメタテーブルを作成し、メタメソッドやメンバー関数などを登録する。
* ``lua_newuserdata``でユーザーデータを作成し、確保されたメモリ上にインスタンスを構築する。
* ``luaL_setmetatable``で作成したユーザーデータに対してメタテーブルを設定する。
例としてシンプルなメンバーを持つTestClassを登録するコード例を以下に示します(lambdaやautoなどC++11の機能を使用しています。)
```C++
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 = [](lua_State* L) {
           TestClass* setget = static_cast<TestClass*>(check_userdata(L, 1, "TestClass"));
           setget->set(lua_tonumber(L, 2));
           return 0;
       };
       auto getf = [](lua_State* L) {
           TestClass* setget = static_cast<TestClass*>(check_userdata(L, 1, "TestClass"));
           lua_pushnumber(L, setget->get());
           return 1;
       };
       auto gcf = [](lua_State* L) {
           TestClass* setget = static_cast<TestClass*>(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を作成して公開してる立場なので、お勧めは言えません。
例えば私の作成しているbinding libraryですと、以下のように記述することで同じようなことが行えます。
```C++
kaguya::State L;
//クラスの登録
L["TestClass"].setClass(kaguya::UserdataMetatable<TestClass>()
   .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())");
```
1 誤字の修正

satoren

satoren score 99

2017/02/04 05:11  投稿

メタテーブルの知識はありますか?
大まかな流れとしては
* ``luaL_newmetatable``でメタテーブルを作成し、メタメソッドやメンバー関数などを登録する。
* ``lua_newuserdata``でユーザーデータを作成し、確保されたメモリ上にインスタンスを構築する。
* ``luaL_setmetatable``で作成したユーザーデータに対してメタテーブルを設定する。
``int get();`` ``void set(int);``をメンバーに持つTestClassを登録するコード例を以下に示します(lambdaやautoなどC++11の機能を使用しています。)
例としてシンプルなメンバーを持つTestClassを登録するコード例を以下に示します(lambdaやautoなどC++11の機能を使用しています。)
```C++
 
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 = [](lua_State* L) {
           TestClass* setget = static_cast<TestClass*>(check_userdata(L, 1, "TestClass"));
           setget->set(lua_tonumber(L, 2));
           return 0;
       };
       auto getf = [](lua_State* L) {
           TestClass* setget = static_cast<TestClass*>(check_userdata(L, 1, "TestClass"));
           lua_pushnumber(L, setget->get());
           return 1;
       };
       auto gcf = [](lua_State* L) {
           TestClass* setget = static_cast<TestClass*>(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へ登録
       //登録したインスタンスのメンバーを呼んでみる
       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を作成して公開してる立場なので、お勧めは言えません。
たくさんありますが、私自身binding libraryを作成して公開してる立場なので、お勧めは言えません。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る