lua绑定C++对象系列四——luna模板

在系列文章二三中描述的绑定C++对象基础篇和进阶篇,都有一个很大的问题,就是每个类需要写大量的代码,从类的元表创建、方法注册到实例创建,都需要自己重复写类似的代码。如果涉及N个不同类,会有大量重复的代码,能否创建一个模板类,把这些重复的代码进行简化,通过模板的方式绑定成不同的类?下面的luna<T>就是完成这样一个壮举,例如针对Car类,只需要luna<Car>::regist(L)即可完成注册。在lua层面 local car = Car()就能自动创建Car对象,然后方便的通过car.xxx()调用成员方法。

 

代码文件luna.h

1 #include <iostream> 2 #include <cstring> 3 extern "C" { 4 #include <lua.h> 5 #include <lualib.h> 6 #include <lauxlib.h> 7 } 8 9 using namespace std; 10 11 #define DECLARE_LUNA_CLASS(obj) \ 12 static const char *name;\ 13 static luna<obj>::TMethod methods[]; 14 15 #define EXPORT_LUNA_FUNCTION_BEGIN(obj) \ 16 const char* obj::name = #obj;\ 17 luna<obj>::TMethod obj::methods[] = { 18 19 #define EXPORT_LUNA_MEMBER_INT(obj, member) \ 20 {#member, nullptr}, 21 22 #define EXPORT_LUNA_FUNCTION(obj, func) \ 23 {#func, &obj::func}, 24 25 #define EXPORT_LUNA_FUNCTION_END(obj) \ 26 {nullptr, nullptr}\ 27 }; 28 29 template<typename T> 30 class luna 31 { 32 public: 33 typedef struct {T* _u;} TObject; 34 typedef int (T::*TPfn)(lua_State* L); 35 typedef struct {const char* name; TPfn pf;} TMethod; 36 public: 37 static int regist(lua_State* L); 38 static int create(lua_State* L); 39 static int call(lua_State* L); 40 static int gc(lua_State* L); 41 }; 42 43 template<typename T> 44 int luna<T>::regist(lua_State* L) 45 { 46 //原表Shape 47 if (luaL_newmetatable(L, T::name)) 48 { 49 //注册Shape到全局 50 lua_newtable(L); 51 lua_pushvalue(L, -1); 52 lua_setglobal(L, T::name); 53 54 //设置Shape的原表,主要是__call,使其看起来更像C++初始化 55 lua_newtable(L); 56 lua_pushcfunction(L, luna<T>::create); 57 lua_setfield(L, -2, "__call"); 58 lua_setmetatable(L, -2); 59 lua_pop(L, 1); //这时候栈只剩下元表 60 61 //设置元表Shape index指向自己 62 lua_pushvalue(L, -1); 63 lua_setfield(L, -2, "__index"); 64 lua_pushcfunction(L, luna<T>::gc); 65 lua_setfield(L, -2, "__gc"); 66 } 67 return 0; 68 } 69 70 template<typename T> 71 int luna<T>::create(lua_State* L) 72 { 73 lua_remove(L, 1); 74 TObject* p = (TObject*)lua_newuserdata(L, sizeof(TObject)); 75 p->_u = new T(); 76 77 luaL_getmetatable(L, T::name); 78 lua_setmetatable(L, -2); 79 80 luaL_getmetatable(L, T::name); 81 for (auto* l = T::methods; l->name; l++) 82 { 83 lua_pushlightuserdata(L,(void*)l); 84 lua_pushlightuserdata(L,(void*)p); 85 lua_pushcclosure(L, luna<T>::call, 2); 86 lua_setfield(L, -2, l->name); 87 } 88 89 lua_pop(L, 1); 90 91 return 1; 92 } 93 94 template<typename T> 95 int luna<T>::call(lua_State* L) 96 { 97 TMethod* v = (TMethod*)lua_topointer(L, lua_upvalueindex(1)); 98 cout<<"luna<T>::call:"<<v->name<<endl; 99 100 TObject* p = (TObject*)lua_topointer(L, lua_upvalueindex(2)); 101 102 103 return ((p->_u)->*(v->pf))(L); 104 } 105 106 template<typename T> 107 int luna<T>::gc(lua_State* L) 108 { 109 TObject* p = (TObject*)lua_touserdata(L, 1); 110 (p->_u)->~T(); 111 return 0; 112 }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwxgpf.html