Skip to content

Instantly share code, notes, and snippets.

@movsb
Created March 10, 2017 17:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save movsb/d76ca744a7328dac61b4ccaf947a5a5b to your computer and use it in GitHub Desktop.
Save movsb/d76ca744a7328dac61b4ccaf947a5a5b to your computer and use it in GitHub Desktop.
在 C++ 中快速创建 LUA 自定义数据类型(带元表)的对象的一种包装方法
#include <cstdio>
#include <string>
#include <iostream>
#include <lua/lua.hpp>
#define LUAAPI(name) static int name(lua_State* L)
#define DECL_OBJECT(T) class T
#define DECL_THIS auto& O = *__this__(L)
#define _BEG_OBJ_API_(N, T) \
static T* __this__(lua_State* L) {return static_cast<T*>(luaL_checkudata(L, 1, __name__()));}\
static const char* const __name__() { return "" #N "::" #T; }\
static const wchar_t* const __namew__() { return L"" #N L"::" #T; }\
static const luaL_Reg* const __apis__() { static luaL_Reg s_apis[] = {
#define BEG_OBJ_API(N, T) LUAAPI(__gc)\
{\
DECL_THIS;\
O.~T();\
return 0;\
}\
_BEG_OBJ_API_(N, T)\
OBJAPI(__gc)
#define OBJAPI(name) {#name, name},
#define END_OBJ_API() {nullptr, nullptr} }; return s_apis; }
// ----------------------------------------------------------------------------
void SetObjectMetatable(lua_State* L, const char* name, const luaL_Reg* fns)
{
if(luaL_getmetatable(L, name) == LUA_TNIL) {
lua_pop(L, 1);
luaL_newmetatable(L, name);
luaL_setfuncs(L, fns, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
}
template<typename T, typename... Args>
T* PushObject(lua_State* L, Args... args)
{
void* m = lua_newuserdata(L, sizeof(T));
auto p = new (m) T(std::forward<Args>(args)...);
SetObjectMetatable(L, T::__name__(), T::__apis__());
return p;
}
// ----------------------------------------------------------------------------
DECL_OBJECT(MyObject)
{
public:
MyObject(int x, const std::string& s)
: _x(x)
, _s(s)
{
std::cout << __FUNCTION__
<< ": x: " << _x
<< ", s: " << _s
<< std::endl;
}
~MyObject()
{
std::cout << __FUNCTION__ << std::endl;
}
BEG_OBJ_API(::, MyObject)
OBJAPI(fun1)
OBJAPI(fun2)
END_OBJ_API()
protected:
LUAAPI(fun1)
{
DECL_THIS;
std::cout << __FUNCTION__ << ": " << O._x << std::endl;
return 0;
}
LUAAPI(fun2)
{
DECL_THIS;
return 0;
}
private:
int _x;
std::string _s;
};
// ----------------------------------------------------------------------------
int main()
{
lua_State* L;
L = luaL_newstate();
PushObject<MyObject>(L, 123, "str");
lua_setglobal(L, "obj");
luaL_dostring(L, R"(obj:fun1() obj = nil)");
lua_close(L);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment