lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> For the Lua-impaired, can you explain how this works?  From 
> looking at it, I don't see where "this" is being passed?
> 
> > typedef int (*LuaStateCFunction)(LuaState state);
> > 
> > class LuaState
> > {
> > public:
> > 	// Functions...
> > 	void Register(const char* funcName, LuaStateCFunction function)
> > 	{
> > 		lua_pushstring(m_state, funcName);
> > 		lua_pushcclosure(m_state, (lua_CFunction)function, 0);
> > 		lua_settable(m_state, m_stackIndex);
> > 	}
> > 
> > protected:
> > 	lua_State* m_state;
> > };
> > 
> > 
> > static int Callback(LuaState state)
> > {
> > 	printf("Hi\n");
> > 	return 0;
> > }
> > 
> > 
> > LuaState state;
> > state.Register("Callback", Callback);

The C++ this pointer from your second question is not being passed in
this code (and can't, either).  You asked how you could change a:

int Callback(lua_State* state)

to use:

int Callback(MyProxy* proxy)  // off the top of my head.

The short answer is that you can't, not without modifying Lua directly.

However, so long as MyProxy has no need of any explicitly set member
variables other than a lua_State* m_state, you can fake it using the
LuaState code above.  (How portable it is, I don't know.)

The Callback() function signature is first munged into a Lua compatible
lua_State* signature.  When the callback function is called with a
lua_State* pointer from Lua, the lua_State* pointer is pushed onto the C
stack.  Callback() expects a LuaState object on the stack at that point.
The constructor for LuaState is never called, since the caller has to
build the object in C++.  That's perfect for this situation, though.
The LuaState object is 4 bytes, exactly the same size as the lua_State*
pointer being passed.  The lua_State* pointer fits nicely into the
LuaState m_state member variable, and all is well.

Phew!  In C++ code, it basically comes down to:

lua_State* state;
LuaState& stateObject = reinterpret_cast<LuaState&>(state);

Where the LuaState object comes in (or your MyProxy) is being able to
encapsulate all Lua function calls with your own functions, thereby
making it easier to use.  My LuaState C++ wrapper does exactly that (for
me, anyway).  The older version of the wrapper, called Script, dealt
with this same problem in this fashion:

int Callback(lua_State* state)
{
    Script script(state);
    script.Function();
    return 0;
}

It was ugly, and has now been replaced with:

int Callback(LuaState state)
{
    state.Function();
    return 0;
}

Even better is the fact that LuaState has a casting operator for
lua_State*, so it can be used seamlessly with basic Lua functions.

In your case, you could actually treat your MyProxy as a smart pointer
and patch it through to wherever you want.

That was lengthy, but hopefully, you'll understand better what I did and
why I did it.

Thanks,
Josh