LuaPlus: как заставить функцию возвращать таблицу?

Мне интересно, как я могу создать и зарегистрировать функцию со стороны C ++, которая возвращает таблицу при вызове со стороны Lua.
Я много чего пробовал, но ничего не получалось. : /

(извините за длинный код)
Это, например, не сработает, потому что 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, он просто падает (0x3) и говорит:
Ошибка подтверждения: 0, файл C: \ …… \luafunction.h, линия 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

РЕДАКТИРОВАТЬ: функция печати исходит от Вот. И было в основном причиной этого не работать. Печать может печатать только строки, а не таблицы … Код C ++, указанный выше, работает нормально, если вы просто вернете 1.

Вот документация, которая пришла с моей версией LuaPlus: http://luaplus.funpic.de/

Я действительно надеюсь, что вы можете помочь мне .. Я уже начинаю думать, что это невозможно. : ‘(

редактировать:
Я совершенно забыл сказать, что использование PushStack () приводит к ошибке, потому что «член не существует» …

6

Решение

После некоторого кропотливого исследования из длинного обсуждения комментариев, я публикую этот ответ, чтобы помочь обобщить ситуацию и, надеюсь, дать несколько полезных советов.

Основная проблема, с которой столкнулся ОП, заключалась в том, что print функция вызывается в тестовом скрипте lua. Вопреки исходному коду, показан реальный код, против которого тестировался OP Print(myVar) которая является пользовательской функцией lua_CFunction, а не встроенной print функция.

Так или иначе, в конечном итоге это привело к созданию template <typename RT> class LuaFunction и вызов перегружен operator()(), Из проверки luafunction.h от luaPlus любые ошибки lua, возникающие в этом вызове, будут проглочены без какой-либо регистрации (не очень хорошее решение для разработки со стороны luaPlus):

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

Чтобы помочь выявить будущие ошибки, подобные этой, я предлагаю добавить новую luaplus_assertlog макро. В частности, этот макрос будет включают errorString так что контекст не полностью потерян и, надеюсь, поможет с отладкой. Это изменение с надеждой не нарушит существующее использование luaplua_assert из других частей API. В конечном счете, вероятно, лучше изменить 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 ++ имеют тенденцию быть тяжелее, чем обычные функции io в стиле C. Это особенно верно, если вы используете mingw в качестве набора инструментов — ld компоновщик не может удалить неиспользуемые символы потока C ++, даже если ваша программа никогда не использует его.

Имея это в виду, вот пример, когда незащищенный вызов делается для функции lua, так что вы можете увидеть errorString распечатано до аварии:

// 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.
1

Другие решения

сначала вы можете попытаться зарегистрировать функцию с помощью RegisterDirect (), это может избежать проблемы lua_CFunction, проверьте руководство luaplus.

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

globals.RegisterDirect("Test",Test);

во-вторых, если я помню, чтобы создать таблицу, есть два решения, как это

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

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

проверьте, правильно ли вы используете функцию.

в-третьих, я помню, что объект стека lua не является объектом luaobject, у них есть преобразование, может быть, вы можете попробовать это

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

далее, как и функция Test (), которую вы дали выше, таблица tableObj, которую вы помещаете в стек lua, вы должны не забыть очистить объект.

1

По вопросам рекламы [email protected]