質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.99%

Luaのグローバル変数にC++のインスタンスを登録するには?

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,254

KureteRubyLua

score 192

Luaのグローバル変数にlua_setglobalなどの関数を使ってintやdoubleといった普通の変数をグローバル変数として登録する方法は分かったのですが、インスタンスをグローバル変数として登録する方法が分かりません。どうすればいいのでしょうか。よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

メタテーブルの知識はありますか?

大まかな流れとしては

  • 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 = [](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ですと、以下のように記述することで同じようなことが行えます。

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())");

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/05 09:08

    どうもありがとうございました

    キャンセル

0

Lua、C++相互に関数を呼び出したいということでしょうか?
下記URLが簡潔でわかりやすいかと思います。

LuaのC++組み込み方自分用まとめ Qiita

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる