如何提高我 Lua 包装函数的简洁性?

我有以下模板特化,将C++函数包装到Lua中:

  template<class ...Args>
  struct Wrapper<void (*)(Args...)> {

    using F = void (*)(Args...);

    static int f (lua_State *L)
    {
      Lua lua(L);

      // 获取函数指针。
      F f = (F) lua_touserdata(L, lua_upvalueindex(1));

      // 构建参数元组。
      auto args = lua.CheckArgs<1, Args...>();

      // 将函数应用于元组。
      FunctionPointer<F> fp(f);
      fp.Apply(args);

      return 0;

    }
  };

  template<class R, class ...Args>
  struct Wrapper<R (*)(Args...)> {

    using F = R (*)(Args...);

    static int f (lua_State *L)
    {
      Lua lua(L);

      // 获取函数指针。
      F f = (F) lua_touserdata(L, lua_upvalueindex(1));

      // 构建参数元组。
      auto args = lua.CheckArgs<1, Args...>();

      // 将函数应用于元组。
      FunctionPointer<F> fp(f);
      lua.Push( fp.Apply(args) );

      return 1;

    }
  };

请注意它们的差异非常小。在第一个特化中,FunctionPointer<F>::Apply返回void。在第二个特化中,它的结果被推到Lua堆栈上。

我能把这两个特化组合成一个吗?

我意识到这可能看起来很吹毛求疵,但是在我的代码的其他地方,我不得不编写许多这样的包装器,因为包装的函数类型有所不同(自由函数、PMF、const或非const)。我一共有14个这样的特化。

这里有另外两个非常相似的特化,它们只通过PMF是否是const来区分:

  template <typename Self, typename ...Args>
  struct MethodWrapper<void (Self::*)(Args...) >
  {
    using F = void (Self::*)(Args...);

    static int f (lua_State *L)
    {
      Lua lua(L);

      F f = *(F *)lua_touserdata(L, lua_upvalueindex(1));
      Self* self = lua.CheckPtr<Self>(1);

      auto args = lua.CheckArgs<2, Args...>();

      FunctionPointer<F> fp(f);
      try {
        fp.Apply(self, args);
      } catch(std::exception& e) {
        luaL_error(L, e.what());
      }

      return 0;
    }
  };

  template <typename R, typename Self, typename ...Args>
  struct MethodWrapper<R (Self::*)(Args...) const >
  {
    // 与上面完全相同
  };

我能避免这种剪切和复制吗? (不使用宏)

相关但需要同样数量的特化:如何使用可变参数模板制作通用的Lua函数包装器?

点赞
用户4323
用户4323

你应该能够制作一个通用的函数器,它接受 fpargslua,并调用 lua.Push(),当 Rvoid 时需要做偏特化处理,只调用函数并忽略 (void) 的结果。然后你可以这样调用它:

ApplyAndPushIfNotVoid<R>()(lua, fp, args);
2015-01-14 07:32:20