首页 文章

作为模板参数,加上可变参数模板参数

提问于
浏览
11

我正在编写一个通用函数包装器,它可以将任何函数包装到具有该形式的lua样式调用中

int lua_function(lua_State * L)

我希望包装函数是即时生成的,所以我想将函数作为模板参数传递 . 如果你知道参数的数量(例如2),这是微不足道的:

template <typename R, typename Arg1, typename Arg2, R F(Arg1, Args)>
struct wrapper

但是,我不知道这个数字,所以我请求variadic模板参数求助

// This won't work
template <typename R, typename... Args, R F(Args...)>
struct wrapper

上面的内容不会编译,因为variadic参数必须是最后一个 . 所以我使用两个级别的模板,外部模板捕获类型,内部模板捕获函数:

template <typename R, typename... Args>
struct func_type<R(Args...)>
{
  // Inner function wrapper take the function pointer as a template argument
  template <R F(Args...)>
  struct func
  {
    static int call( lua_State *L )
    {
      // extract arguments from L
      F(/*arguments*/);
      return 1;
    }
  };
};

这是有效的,除了包装像这样的函数

double sin(double d) {}

用户必须写

func_type<decltype(sin)>::func<sin>::apply

这很乏味 . 问题是:有没有更好的,用户友好的方式来做到这一点? (我不能用函数模板来包装整个东西,因为函数参数不能用作模板参数 . )

2 回答

  • 0

    std::functionstd::result_of 之类的东西使用以下技术来做你想要的变量模板:

    template<typename Signature>
    struct wrapper; // no base template
    
    template<typename Ret, typename... Args>
    struct wrapper<Ret(Args...)> {
        // instantiated for any function type
    };
    

    你可以扩展上面的内容来添加一个非类型 Ret(&P)(Args...) 模板参数(指向函数的指针也是如此),但你仍然需要在用户级别 decltype ,即 wrapper<decltype(sin), sin>::apply . 可以说,如果您决定使用宏来删除重复,那么它将是预处理器的合法使用 .

    template<typename Sig, Sig& S>
    struct wrapper;
    
    template<typename Ret, typename... Args, Ret(&P)(Args...)>
    struct wrapper<Ret(Args...), P> {
        int
        static apply(lua_State*)
        {
            // pop arguments
            // Ret result = P(args...);
            // push result & return
            return 1;
        }
    };
    
    // &wrapper<decltype(sin), sin>::apply is your Lua-style wrapper function.
    

    以上编译与ideone的gcc-4.5 . 运行应用程序(可变地)弹出参数,祝你好运(如果你打开一个关于那个的问题,请给我留言) . 你考虑过使用Luabind吗?

  • 9

    正如@Juraj在他的评论中所说,函数指针可以是模板参数,请参阅以下简单示例:

    #include <iostream>
    #include <boost/typeof/typeof.hpp>
    
    void f(int b, double c, std::string const& g)
    {
      std::cout << "f(): " << g << std::endl;
    }
    
    template <typename F, F* addr>
    struct wrapper
    {
      void operator()()
      {
        std::string bar("bar");
        (*addr)(1, 10., bar);
      }  
    };
    
    int main(void)
    {
      wrapper<BOOST_TYPEOF(f), &f> w;
      w();
      return 0;
    }
    

    工作版:http://www.ideone.com/LP0TO

    我正常使用 BOOST_TYPEOF ,因为我总是在当前标准中提供示例,但它的作用类似于 decltype . 这是你追求的吗?

相关问题