6

Lua 側から呼び出されたときにテーブルを返す関数を C++ 側から作成して登録する方法を知りたいです。
私は多くのことを試しましたが、何もうまくいきませんでした。:/

(長いコードで申し訳ありません) Register() は「luaCFunction」スタイルの関数を想定しているため、たとえばこれは機能しません。

LuaPlus::LuaObject Test( LuaPlus::LuaState* state ) {
    int top = state->GetTop();
    std::string var( state->ToString(1) );

    LuaPlus::LuaObject tableObj(state);
    tableObj.AssignNewTable(state);

    if (var == "aaa")
        tableObj.SetString("x", "ABC");
    else if (var == "bbb")
        tableObj.SetString("x", "DEF");
    tableObj.SetString("y", "XYZ");
    return tableObj;
}
int main()
{
    LuaPlus::LuaState* L = LuaPlus::LuaState::Create(true);
     //without true I can't access the standard libraries like "math.","string."...
     //with true, GetLastError returns 2 though (ERROR_FILE_NOT_FOUND)
     //no side effects noticed though

    LuaPlus::LuaObject globals = L->GetGlobals();

    globals.Register("Test",Test);

    char pPath[MAX_PATH];
    GetCurrentDirectory(MAX_PATH,pPath);
    strcat_s(pPath,MAX_PATH,"\\test.lua");
    if(L->DoFile(pPath)) {
        if( L->GetTop() == 1 ) // An error occured
            std::cout << "An error occured: " << L->CheckString(1) << std::endl;
    }
}

luaCFunction-function として設定しようとすると、クラッシュ (0x3) して次のように表示されます:
Assertion failed: 0, file C:\......\ luafunction.h , line 41

int Test( LuaPlus::LuaState* state ) {
    int top = state->GetTop();
    std::string var( state->ToString(1) );

    LuaPlus::LuaObject tableObj(state);
    tableObj.AssignNewTable(state);

    if (var == "aaa")
        tableObj.SetString("x", "ABC");
    else if (var == "bbb")
        tableObj.SetString("x", "DEF");
    tableObj.SetString("y", "XYZ");

    tableObj.Push();

    return state->GetTop() - top;
}

明確にするために:Lua側から、次のように呼び出し可能にしたかった:

myVar = Test("aaa")
Print(myVar) -- output: ABC

編集: 印刷機能はhereから来ます。そして、基本的にこれが機能しない原因でした。Print は、テーブルではなく文字列のみを出力できます...上記の C++ コードは、1 を返すだけで正常に動作します。

これは私の LuaPlus バージョンに付属のドキュメントです: http://luaplus.funpic.de/

あなたが私を助けてくれることを本当に願っています..私はすでにそれが不可能だと考え始めています. :'(

編集: 「メンバーが存在しない」ため、 PushStack() を使用するとエラーが発生することを完全に忘れていました...

4

2 に答える 2

1

まず、RegisterDirect() を使用して関数の登録を試みることができます。これにより、lua_CFunction の問題を回避できます。luaplus のマニュアルを確認してください。

LuaPlus::LuaObject globals = L->GetGlobals();

globals.RegisterDirect("Test",Test);

2番目に、テーブルを作成することを覚えている場合、このように2つの解決策があります

//first
LuaObject globalsObj = state->GetGlobals();  
LuaObject myArrayOfStuffTableObj = globalsObj.CreateTable("MyArrayOfStuff"); 

//second
LuaObject aStandaloneTableObj;  
aStandaloneTableObj.AssignNewTable(state);  

正しい機能を使用しているかどうかを確認してください。

3 番目に、lua スタック オブジェクトが luaobject ではないことを覚えています。それらには変換があります。これを試すことができるかもしれません

LuaStackObject stack1Obj(state, 1);
LuaObject nonStack1Obj = stack1Obj;

上記の関数 Test() のように、lua スタックにプッシュしたテーブル tableObj のように、オブジェクトをクリアすることを忘れないでください。

于 2013-11-13T13:08:43.673 に答える
1

長いコメントの議論から骨の折れる調査を行った後、この回答を投稿して状況を要約し、役立つアドバイスを提供できることを願っています.

OP が直面していた主な問題は、lua テスト スクリプトで間違ったprint関数が呼び出されていたことです。元のコードとは対照的に、OP がテストしていた実際のコードはPrint(myVar)、組み込み関数ではなくカスタム提供の lua_CFunction を呼び出していましたprint

どういうわけか、これはtemplate <typename RT> class LuaFunctionオーバーロードされた のインスタンス化と呼び出しを作成することになりましたoperator()()。luaPlusから を検査すると、luafunction.hこの呼び出し内で発生した lua エラーは、ログに記録されずに飲み込まれます (luaPlus 側の設計上の決定は適切ではありません)。

  if (lua_pcall(L, 0, 1, 0)) {
      const char* errorString = lua_tostring(L, -1);  (void)errorString;
      luaplus_assert(0);
  }

このような将来のエラーをキャッチするために、新しいluaplus_assertlogマクロを追加することをお勧めします。具体的には、このマクロには が含まれているerrorStringため、コンテキストが完全に失われることはなく、うまくいけばデバッグに役立ちます。この変更により、API の他の部分からの既存の使用が中断されないことを願っています。luaplua_assertただし、長期的luaplus_assertには、実際に意味のあるものを含むように変更した方がよいでしょう。

とにかく、ここに加えられた変更の差分があります:

LuaPlusInternal.h

@@ -81,5 +81,6 @@
 } // namespace LuaPlus

 #if !LUAPLUS_EXCEPTIONS
+#include <stdio.h>
 #include <assert.h>
 #define luaplus_assert(e) if (!(e)) assert(0)
@@ -84,5 +85,6 @@
 #include <assert.h>
 #define luaplus_assert(e) if (!(e)) assert(0)
+#define luaplus_assertlog(e, msg) if (!(e)) { fprintf(stderr, msg); assert(0); }
 //(void)0
 #define luaplus_throw(e) assert(0)
 //(void)0

LuaFunction.h

@@ -21,7 +21,7 @@
 class LuaFunction
 {
 public:
-   LuaFunction(LuaObject& _functionObj)
+   LuaFunction(const LuaObject& _functionObj)
    : functionObj(_functionObj) {
  }

@@ -36,7 +36,7 @@

    if (lua_pcall(L, 0, 1, 0)) {
      const char* errorString = lua_tostring(L, -1);  (void)errorString;
-           luaplus_assert(0);
+           luaplus_assertlog(0, errorString);
    }
    return LPCD::Type<RT>::Get(L, -1);
  }

std::cerr上記の変更では、C++ ストリームは単純な古い C スタイルの io 関数よりも重い傾向があるという単純な理由から、使用しないことを選択しました。これは、ツールチェーンとして mingw を使用している場合に特に当てはまります。ldリンカーは、プログラムが使用していない場合でも、未使用の C++ ストリーム シンボルを削除できません。

errorStringこれで、保護されていない呼び出しが lua 関数に対して行われ、クラッシュの前に出力されたものを見ることができる例を次に示します。

// snip...
int main(int argc, const char *argv[])
{
    LuaStateAuto L ( LuaState::Create(true) );
    LuaObject globals = L->GetGlobals();
    globals.Register("Test", Test);
    globals.Register("Print", Print);
    if(argc > 1)
    {
      /*
      if (L->DoFile(argv[argc - 1]))
        std::cout << L->CheckString(1) << '\n';
      /*/
      L->LoadFile( argv[argc - 1] );
      LuaFunction<int> f ( LuaObject (L, -1) );
      f();
      //*/
    }
}

上記を実行すると、クラッシュが発生しますが、ある程度役立つエラー メッセージが表示されます。

g++ -Wall -pedantic -O0 -g   -I ./Src -I ./Src/LuaPlus/lua51-luaplus/src plustest.cpp -o plustest.exe lua51-luaplus.dll

plustest.exe plustest.lua
plustest.lua:2: bad argument #1 to 'Print' (string expected, got table)Assertion failed!

Program: G:\OSS\luaplus51-all\plustest.exe
File: ./Src/LuaPlus/LuaFunction.h, Line 39

Expression: 0

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
于 2013-11-16T02:24:12.240 に答える