Luna Wrapper

lua-users home
wiki

LunaWrapper是一個簡短(53 行)的 wrapper,旨在提供相對簡單地於 Lua 中存取 C++ 類別的方式。受[1]啟發,更新適用於 Lua 5.1。作者為 nornagon。依據 BSD 2 條款授權[2]提供。

LunaFour提供額外的功能,例如屬性(需要修改 Lua)和從 C++ 擷取及傳回類別的函式。

template<class T> class Luna {
  public:
    static void Register(lua_State *L) {
      lua_pushcfunction(L, &Luna<T>::constructor);
      lua_setglobal(L, T::className);

      luaL_newmetatable(L, T::className);
      lua_pushstring(L, "__gc");
      lua_pushcfunction(L, &Luna<T>::gc_obj);
      lua_settable(L, -3);
    }

    static int constructor(lua_State *L) {
      T* obj = new T(L);

      lua_newtable(L);
      lua_pushnumber(L, 0);
      T** a = (T**)lua_newuserdata(L, sizeof(T*));
      *a = obj;
      luaL_getmetatable(L, T::className);
      lua_setmetatable(L, -2);
      lua_settable(L, -3); // table[0] = obj;

      for (int i = 0; T::Register[i].name; i++) {
        lua_pushstring(L, T::Register[i].name);
        lua_pushnumber(L, i);
        lua_pushcclosure(L, &Luna<T>::thunk, 1);
        lua_settable(L, -3);
      }
      return 1;
    }

    static int thunk(lua_State *L) {
      int i = (int)lua_tonumber(L, lua_upvalueindex(1));
      lua_pushnumber(L, 0);
      lua_gettable(L, 1);

      T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
      lua_remove(L, -1);
      return ((*obj)->*(T::Register[i].mfunc))(L);
    }

    static int gc_obj(lua_State *L) {
      T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
      delete (*obj);
      return 0;
    }

    struct RegType {
      const char *name;
      int(T::*mfunc)(lua_State*);
    };
};

class Foo {
  public:
    Foo(lua_State *L) {
      printf("in constructor\n");
    }

    int foo(lua_State *L) {
      printf("in foo\n");
    }

    ~Foo() {
      printf("in destructor\n");
    }

    static const char className[];
    static const Luna<Foo>::RegType Register[];
};

const char Foo::className[] = "Foo";
const Luna<Foo>::RegType Foo::Register[] = {
  { "foo", &Foo::foo },
  { 0 }
};

接著在初始化期間的某個地方

Luna<Foo>::Register(L);

從 lua

local foo = Foo()
foo:foo()

稍後

lua_close(L);

結果

in constructor
in foo
in destructor

另請參閱

注意

如果您想要直接在 Lua 中建立類別並取得指標以設定一些值,那麼您可以將此函式新增至 Luna 類別。我在實作 Lua 到 C++ 方面還很生疏,因此可能會有更好的方法可以做到這點,我樂意看到這些做法。
	// Directly add the new class
	static T* RegisterTable(lua_State *L)
	{
		luaL_newmetatable(L, T::className);
		lua_pushstring(L, "__gc");
		lua_pushcfunction(L, &Luna<T>::gc_obj);
		lua_settable(L, -3);

		T* obj = new T(L);
		lua_newtable(L);
		lua_pushnumber(L, 0);
		T** a = (T**)lua_newuserdata(L, sizeof(T*));
		*a = obj;
		luaL_getmetatable(L, T::className);
		lua_setmetatable(L, -2);
		lua_settable(L, -3); // table[0] = obj;
		for (int i = 0; T::Register[i].name; i++)
		{
			lua_pushstring(L, T::Register[i].name);
			lua_pushnumber(L, i);
			lua_pushcclosure(L, &Luna<T>::thunk, 1);
			lua_settable(L, -3);
		}
		lua_setglobal(L, T::className);
		return obj;
	}

近期變更 · 喜好設定
編輯 · 歷史記錄
最近於 2014 年 5 月 7 日上午 1:32 GMT 編輯(diff)