Using the Lua C API, I registered a simple Object
class to Lua, like this:
// My C++ Object class
class Object {
private:
double x;
public:
Object(double x) : x(x){}
};
// Create and return instance of Object class to Lua
int object_new(lua_State* L)
{
double x = luaL_checknumber(L, 1);
*reinterpret_cast<Object**>(lua_newuserdata(L, sizeof(Object*))) = new Object(x);
luaL_setmetatable(L, "Object");
return 1;
}
// Functions to register to Lua
const luaL_Reg functions[] =
{
{"new", object_new},
{nullptr, nullptr}
};
// Register the Object class to Lua
luaL_newmetatable(L, "Object");
luaL_setfuncs(L, functions, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
In my Lua script, the following works just fine:
// Works!
my_object = Object.new(42)
But, I would like to be able to do this (i.e. omit the .new
part):
// Fail :(
my_object = Object(42)
But when I execute the Lua script, I get this error:
...attempt to call a table value (global 'Object').
Is there a way to register a C++ class in a way that the constructor gets called if we don't provide a function name? What did I miss to make this work? That would be particularly useful for temporary objects.
Thanks!
You should check the return of luaL_newmetatable to register your metamethods just once.
You can replace luaL_setmetatable
by luaL_newmetatable
, so your code is compatible to Lua 5.1, you can embed the metatable registration into the constructor and it works the same (except the additional lua_setmetatable
).
For a constructor, just register a function. The metatable should manage an instance, not his creation.
Don't forget to add a deconstructor (__gc) to free your allocated C++ class instance.
At the end you have just to register function Object
which creates the metatable at his first call.
#define LUA_META_OBJECT "Object"
class Object {
private:
double x;
public:
Object(double x) : x(x){}
};
static int object_free(lua_State* L)
{
delete *static_cast<Object**>(luaL_checkudata(L, 1, LUA_META_OBJECT));
return 0;
}
static int object_new(lua_State* L)
{
const lua_Number x = luaL_checknumber(L, 1);
*static_cast<Object**>(lua_newuserdata(L, sizeof(Object*))) = new Object(x);
if(luaL_newmetatable(L, LUA_META_OBJECT)){
static const luaL_Reg functions[] =
{
{"__gc", object_free},
{nullptr, nullptr}
};
luaL_setfuncs(L, functions, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}
...
lua_register(L, "Object", object_new);
...