1
votes

I'm trying to add the LUA API to my C++ program, and I'm attempting to allow the script to draw to my GUI. So far, I have this for my lambda function:

auto addToDrawList = [](lua_State* L) -> int
{
    int DrawType = (int)lua_tonumber(L, -2);
    std::string Label = (std::string)lua_tostring(L, -1);

    bool found = false;
    for (int i = 0; i <= DrawList.size(); i++)
    {
        if (DrawList[i].Active == false && !found)
        {
            switch (DrawType)
            {
            case(0):
                break;
            case(1):
                DrawList[i].Active = true;
                DrawList[i].DrawType = Type::TextBox;
                DrawList[i].Label = Label;
                break;
            }
            found = true;
        }
    }

    return 0;
};

This as my LUA script being run:

const char* LUA_FILE = R"(
    addToDrawList(1, "Test")
)";

This is how I'm pushing my function to the LUA stack:

lua_State* L = luaL_newstate();

lua_newtable(L);
int uiTableInd = lua_gettop(L);
lua_pushvalue(L, uiTableInd);
lua_setglobal(L, "Ui");

lua_pushcfunction(L, addToDrawList);
lua_setfield(L, -2, "addToDrawList");

The problem is within my first script, as it can't get to the 'DrawList' array as its inside of this.

So, to resolve it, I tried to add this to the lambda's capture list by doing this:

auto addToDrawList = [this](lua_State* L) -> int

Which appeared to work and resolve the error, but then I had an issue with the last script:

lua_pushcfunction(L, addToDrawList);

Error

I've been searching the Internet for a fix, but I can't find any.

1
lua_pushcfunction is a C function, it only knows about C data-types like plain simple function pointers. A captureless lambda can be converted into a plain simple function pointer, but when you add captures it's no longer possible. - Some programmer dude
On a side note, i <= DrawList.size() will go out of bounds of the DrawList. You need to use < instead. - Remy Lebeau
thanks so much Remy i always used to -1 instead of < thanks thats so obvious when i think about it - Conni Bilham

1 Answers

1
votes

lua_pushcfunction() takes a C-style function pointer. A capture-less lambda can be converted to such a function pointer, but a capturing lambda cannot.

Use lua_pushcclosure()1 instead. It will allow you to associate user-defined values (known as upvalues) with the C function, such as your this pointer, or just a pointer to DrawList, etc.

When a C function is created, it is possible to associate some values with it, thus creating a C closure (see ยง3.4); these values are then accessible to the function whenever it is called. To associate values with a C function, first these values should be pushed onto the stack (when there are multiple values, the first value is pushed first). Then lua_pushcclosure is called to create and push the C function onto the stack, with the argument n telling how many values should be associated with the function. lua_pushcclosure also pops these values from the stack.

1: lua_pushcfunction() is just a wrapper for lua_pushcclosure() with 0 upvalues defined.

For example:

auto addToDrawList = [](lua_State* L) -> int
{
    const MyClassType *pThis = (const MyClassType*) lua_topointer(L, lua_upvalueindex(1));

    // use pThis->DrawList as needed...

    return 0;
};

...

lua_State* L = luaL_newstate();
...
//lua_pushcfunction(L, addToDrawList);
lua_pushlightuserdata(L, this);
lua_pushcclosure(L, addToDrawList, 1);
...