Erunehtar
Erunehtar

Reputation: 1693

Self pointer, in C++ function from Lua

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!

Upvotes: 0

Views: 1208

Answers (2)

Milan
Milan

Reputation: 141

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

Upvotes: 0

Nomad010
Nomad010

Reputation: 283

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;
}

Upvotes: -2

Related Questions