【问题标题】:Clean implementation of function template taking function pointer采用函数指针的函数模板的干净实现
【发布时间】:2013-09-13 02:33:20
【问题描述】:

我已经设法实现并测试了我的函数包装器实现,但是,接口并没有它应有的那么好:

template < typename F, F* f >
void register_function( const char* name )
{
    int (*lf) (lua_State *) = function_wrapper< F, f >;
    register_native_function( lf, name );
}

虽然这按预期工作,但使用需要显式模板参数:

register_function< decltype(hello), &hello >( "hello" );

显然第一个参数可以从第一个参数推导出来,所以理想情况下我只想有

register_function< &hello >( "hello" );

有可能吗?有没有更简洁的方法?


更新:回答问题,为什么参数模板化而不是传递:

许多绑定器(包括​​ Lua 绑定器,因为它是专门为 Lua 设计的)通过值传递函数:

register_function("hello", &hello);

这确实更具可读性,并且从界面方面更容易实现。但这也意味着函数的地址需要存储在某个地方。

要将函数绑定到 Lua,我们需要它具有以下原型:

int (*lua_CFunction) (lua_State *)

没有传递其他信息,因此这是我们从 Lua 调用绑定函数时获得的条目和信息。

如果绑定是在编译时完成的,我们可以在从 Lua 执行的代码中提供一个单独的函数(通过模板),从而为我们提供与手写绑定相当的性能,特别是如果编译器优化了样板文件代码。

如果绑定是在运行时完成的,那么我们就不能创建新函数,需要一个全局函数,它知道它应该将调用调度到哪个函数。通常,我们根本无法获取信息,但现有的编译时 Lua 绑定器利用 Lua 自定义的每函数用户数据或闭包来存储执行执行所需的附加信息。但是,与手写绑定相比,这对性能有很大影响,因为可能会分配额外的内存和闭包调度。

我在以前的绑定实现中遇到了运行时版本的性能问题(尽管压力很大),最终将压力最大的部分重写为手写绑定,并且考虑到这次我打算在实时渲染循环中进行lua调用,我想找到一个更接近手写性能的解决方案。

如果我们将函数作为参数传递,我们显然无法在编译时创建函数绑定。

【问题讨论】:

  • 即使第一个参数显然可以“从第一个参数推导出来”,我怀疑您是否可以从第二个参数推导出第一个参数。
  • 是的,但我只想简化一个参数:)。
  • register_function("hello", &amp;hello); 会出现什么问题(即,为什么您首先要将此作为模板参数?)
  • @David,我已经更新了问题。
  • @KornelKisielewicz:我没有看到问题的代码中绑定了任何其他信息,只是想弄清楚要解决的真正问题以及是否有更好的方法。正如您已经注意到模板非类型参数不在可推导的上下文中,因此它的类型必须是已知的(在您的情况下作为第一个参数传递)但取决于确切的实际问题,可能有一些替代品不多比你提到的手动绑定性能差

标签: c++ templates c++11 function-pointers


【解决方案1】:

对不起,戴夫,你不能那样做。

已经提出了在模板类型列表中稍后从文字类型推导出模板类型的提议。最后我检查了一下,它不会进入 C++1y(又名 C++14)。

在语言添加该功能之前,宏可能会有所帮助:

#define REGFUNC( F ) decltype(F), (F)
register_function< REGFUNC(hello) >( "hello" );

还有人谈到在 C++ 中添加“lambda 到 C 函数”支持(能够采用 有状态 lambda,并要求它生成一个使用该状态调用它的 C 函数) ,但我不知道进展如何。

【讨论】:

  • 推导类型有点意思,有提案文件吗?是的,宏会减少打字,但宏太邪恶了:(。
  • @KornelKisielewicz 我不记得我在哪里看到了它:基本上,它允许将 template 类的名称用作构造函数,以及 template 类的类型从中推导出来。即,自动化make_foo( t ),因此您只需foo(t)。可能是在阅读 C++1y 的一些提案时。
  • @Yakk,很好的答案和提示。 decltype(&amp;F) 有什么原因不能在模板中使用吗?这样就不需要推断类型。但是我无法让它在stackoverflow.com/questions/33435553/… 工作(我在其中引用了你的答案)。
【解决方案2】:

将这个问题的六岁添加到标记语言版本:C++17 允许使用占位符声明模板参数。

template < auto &F >
void register_function( const char* name )
{
    int (*lf) (lua_State *) = function_wrapper< std::remove_reference_t<decltype(F)>, F >;
    register_native_function( lf, name );
}

这对函数特别有用,因为概念类型“可调用”实际上是许多 C++ 类型。 (使用参考有助于避免像register_function&lt;2&gt;("?!") 这样的愚蠢事情。)

【讨论】:

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