【问题标题】:functions as template argument, plus variadic template argument作为模板参数的函数,加上可变参数模板参数
【发布时间】:2011-08-26 09:15:44
【问题描述】:

我正在编写一个通用函数包装器,它可以将任何函数包装成一个 lua 风格的调用,其形式为

int lua_function(lua_State *L)

我希望包装函数是即时生成的,所以我正在考虑将该函数作为模板参数传递。如果您知道参数的数量(例如 2),这很简单:

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

但是,我不知道数字,所以我请求可变参数模板参数的帮助

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

上面不会编译,因为可变参数必须是最后一个。所以我使用了两级模板,外层模板捕获类型,内层模板捕获函数:

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

这很乏味。 问题是:有没有更好、对用户更友好的方法呢? (我不能使用函数模板来包装整个东西,因为函数参数不能用作模板参数。)

【问题讨论】:

标签: c++ c++11


【解决方案1】:

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(&amp;P)(Args...) 模板参数(指向函数的指针也可以正常工作),但您仍然需要用户级别的 decltype,即 wrapper&lt;decltype(sin), sin&gt;::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.

以上代码使用 gcc-4.5 在ideone 编译。 祝你好运实现(可变地)弹出参数的应用程序(如果您对此提出问题,请给我留言)。您是否考虑过使用 Luabind?

【讨论】:

  • 谢谢 Luc,我认为这几乎是我们可以在没有宏的情况下获得的。顺便说一句,为了我的目的(包装简单的 c++ 函数),编写“应用”很容易,我只编写了一堆名为 extract_arg 的模板专业化并执行此 statci apply(lua_State *L) { P(extract_arg( L)...); }
【解决方案2】:

正如@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。这就是你所追求的吗?

【讨论】:

    猜你喜欢
    • 2016-11-18
    • 2016-12-01
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多