Мне интересно, как я могу создать и зарегистрировать функцию со стороны 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 () приводит к ошибке, потому что «член не существует» …
После некоторого кропотливого исследования из длинного обсуждения комментариев, я публикую этот ответ, чтобы помочь обобщить ситуацию и, надеюсь, дать несколько полезных советов.
Основная проблема, с которой столкнулся ОП, заключалась в том, что 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.
сначала вы можете попытаться зарегистрировать функцию с помощью 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, вы должны не забыть очистить объект.