lua-users home
lua-l archive

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

[Apologies for posting this twice - I read through it after posting it and
found a few things I wanted to correct...]

> I am trying to register a C++ object method to be called from the
> lua enviroment...

I wanted to do something similar - have lua code call non-static member
functions. You can do this in a fairly neat way with closures. Define a
non-static function that takes a function name, and register that function
under different names, using the required function name or other id as a
closure parameter.

This works great if your class is single-instance, for classes where you
have multiple instances, you could have lua pass a this pointer as the first
parameter to each function (this technique was demonstrated by David Jeske
in a previous reply).

In the code below, the key points are as follows:

1) CLua::s_FuncMap maps function names onto member function pointers
2) we keep our single instance ptr in s_pThis
3) The CLua constructor registers each function as a closure that actually
   calls CLua::DespatchFunction with the required function as the 1st param
4) CLua::DespatchFunction is a static member that looks up the relevant
   non-static member function and calls it through s_pThis

You can achieve the same thing by defining and registering a static member
that calls the non-static through s_pThis, but this method improves
maintainability if you have lots of non-static functions, and opens up a few
other possibilities.

I've simplied this code as much as possible to make the general idea
clearer. With a bit of work you could build a multiple instance class, or
class that can serve as a general base class for this sort of thing. The
closure parameter could also be simply an index into the s_FuncMap array,
which would remove the need for searching in DespatchFunction.

// example.cpp (example.h is below!)

#include "example.h"

//one and only class instance
CLua* CLua::s_pThis=NULL;

//function table
#define MAP_FUNCTION(name) {#name, CLua::name},

//new functions are added simply by writing a new member
//function and including it in this table
FunctionMap CLua::s_FuncMap[]=

	//Register functions. Each function is registered as a
	//call to DespatchFunction, giving a closure which features
	//the real function name. The despatch function ensure the
	//correct member gets called. This makes it easy to use
	//non-static member functions as handlers

	for (int n=0; s_FuncMap[n].pszName; n++)
		lua_pushcclosure(CLua::DespatchFunction, 1);

    //store our one-and-only ptr


//non static function despatcher
void CLua::DespatchFunction(void)

	//function name is first parameter, passed as
	//as closure
	LPCSTR pszFunc=lua_getstring(lua_getparam(1));

	for (int n=0; s_FuncMap[n].pszName; n++)
		if (lstrcmp(s_FuncMap[n].pszName, pszFunc)==0)
			//call function

	//unknown function name

//example function - note that we need to know how many
//parameters to skip before we get the 'real' parameters
void CLua::ExampleFunc1(void)
	CString str;
	int nParam=CLOSURE_PARAMS+1;
	for (lua_Object obj=lua_getparam(nParam);

	MessageBox(NULL, str, "ExampleFunc1", MB_OK);

// example.h

//typedef of a non-static lua callback
typedef void (CLua::* LuaFunction)(void);

//maps function names onto member function pointers
struct FunctionMap
	LPCSTR pszName;
	LuaFunction pfnHandler;

//count of closure params
const int CLOSURE_PARAMS=1;

//example class
class CLua
    virtual ~CLua();

	static CLua* s_pThis;
	static FunctionMap s_FuncMap[];

//members called by DespatchFunction
	void ExampleFunc1(void);
	void ExampleFunc2(void);

//statics called by LUA
	static void DespatchFunction(void);