0
votes

I'm still very new to Lua and I have a hard time trying to figure out the best approach when registering C functions in Lua, but from a C++ class, when it comes to retrieving the self pointer from an object that was not created from Lua.


Consider the following code:

foo.h

class Foo
{
public:
    static int lua_DoSomething(lua_State* pState);
    void DoSomething();
};

foo.cpp

static const luaL_Reg methods[] =
{
    {"DoSomething", Foo::lua_DoSomething},
    {nullptr, nullptr}
};

extern "C"
{
    int luaopen_Foo(lua_State* pState)
    {
        luaL_register(pState, "Foo", methods);
        return 1;
    }
}

int Foo::lua_DoSomething(lua_State* pState)
{
    Foo* self = ???; //<-- how to get self pointer here?
    self->DoSomething();
    return 0;
}

void Foo::DoSomething()
{
    //...
}

script.lua

Foo.DoSomething();

So I got the function registered just fine and Foo::lua_DoSomething gets called (yay!).

However, since the Foo object is not created from Lua, how would I go to get the self pointer in function Foo::lua_DoSomething?

Do I have to register some kind of Foo::GetInstance function to Lua, to get the Foo pointer, and then use it in the Lua script somehow?

And what if there's multiple instance of Foo?

What's the cleanest general approach for objects not created from Lua?

Thanks!

2
Are you sure that compiles without even a warning? Anyway, the first argument on the Lua-stack will be the object it should be executed on. Which might refer to your Foo, or not. - Deduplicator
@Deduplicator Of course the line Foo* self = ???; will not compile, it was just to highlight the location where I needed help. Anyway, how would the Lua stack contain the pointer of my C++ object if the object wasn't created by Lua? - Deathicon
You say lua doesn't create Foo but you still need to get a hold of a Foo instance somehow. How is your lua-C binding API setup to do that currently? Milan's answer is likely the most helpful. - greatwolf
in your case I'd recomment to start first by using a dedicated wrapper, such as LuaBridge or LuaBind - Dmitry Ledentsov

2 Answers

0
votes

You need to pass some information in the lua state, which will help you identify the "self". For example you can store all created instances of the Foo class in map, associate an instance with some identifier (int id), or just pass the pointer of the instance cast to size_t. Then in the lua_DoSomething method, get that information from the lua state, cast it to the Foo instance and you have the "self".

post edit: I am not very familiar with lua from this side (I have done some scripting in lua). But...
In lua you can store data and you can exchange this data between lua and C++. I guess you have counter part of C++ Foo in lua, lets name it LFoo.
Foo in C++ has the method DoSomething and I guess you want to do same in lua (I know you can't have classes in lua but there are ways to mimic it with tables). Foo instance has it's address (this). Pass this address to lua and store the value in table of LFoo. When you call the DoSomething function in lua, this function will call static method lua_DoSomething, pass the value from LFoo table through lua_state back to that method. Use it to get "this".

Try to use something like this:

void RegisterFoo(lua_state* pState, Foo* foo)
{
    Foo** p = (Foo**)lua_newuserdata(pState,sizeof(foo));
    *p = foo;
    ...
}

int Foo::lua_DoSomething(lua_State* pState)
{
    // pass the pointer at first index for example
    Foo* self = (Foo*)lua_topointer(pState,0);
    self->DoSomething();
    return 0;
}

I have found this explanation of these functions:
http://pgl.yoyo.org/luai/i/lua_newuserdata
http://pgl.yoyo.org/luai/i/lua_topointer

-2
votes

In member functions of type Foo, the 'this' pointer is provided for you automatically. Its type is of const Foo*. It is not normally necessary, because in most cases you can just use the member directly. Eg: you can replace:

int Foo::lua_DoSomething(lua_State* pState)
{
  this->DoSomething();
  return 0;
}

with

int Foo::lua_DoSomething(lua_State* pState)
{
    DoSomething();
    return 0;
}