Created
March 10, 2017 17:10
-
-
Save movsb/d76ca744a7328dac61b4ccaf947a5a5b to your computer and use it in GitHub Desktop.
在 C++ 中快速创建 LUA 自定义数据类型(带元表)的对象的一种包装方法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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