C++模板将函数转换为函数对象类型

mar*_*ack 5 c++ templates template-meta-programming c++11

我正在尝试使用std::unique_ptr自定义删除器来简化管理从各种 C API 返回给我的句柄的生命周期。这在理论上很好,但我正在努力寻找一种既在运行时最佳,又没有针对每种包装类型的样板文件堆的方法。

例如,考虑一些不透明类型foo,必须通过将其指针传递给来释放它destroy_foo

// approach 1: pass destroy_foo at runtime (bad for performance)
using foo_ptr = std::unique_ptr<foo, decltype(&destroy_foo)>;
foo_ptr bar{create_foo(...), destroy_foo};


// approach 2: make a deleter type (verbose - for many types)
struct foo_deleter
{
  void operator()(foo* p)
  {
    destroy_foo(p);
  }
};
using foo_ptr = std::unique_ptr<foo, foo_deleter>;
foo_ptr bar{create_foo(...)};
Run Code Online (Sandbox Code Playgroud)

第一种方法很难让编译器优化,因为我传递了一个函数指针,所以它被淘汰了。第二种方法似乎不必要地冗长。我有很多这样的类型想要管理,为每个类型手动创建一个类是很痛苦的。

如何定义一个类模板,它接受destroy_foo并给我一个相当于 的类型foo_deleter?或者有一个标准库模板可以做到这一点吗?

// best of both worlds - to_obj<Func> makes foo_deleter from destroy_foo...
using foo_ptr = std::unique_ptr<foo, to_obj<destroy_foo>>;
foo_ptr bar{create_foo(..)};
Run Code Online (Sandbox Code Playgroud)

因此,给定任何函数,模板将定义一个类,该类operator()简单地将所有参数转发给函数,并返回结果。

n. *_* m. 5

就像是

template<typename T, void (*func)(T*)>
struct Deleter{
  void operator()(T* t) { func(t); }
};
Run Code Online (Sandbox Code Playgroud)

??

或者如果你想要更强大的东西

template <typename t>
struct function_traits;

template <typename R, typename A>
struct function_traits<R (*)(A)>
{
   using t_ret = R;
  using t_arg = A;
};

template <typename F, F* f>
struct Functor
{
  using FT = function_traits<F*>;
  typename FT::t_ret operator()(typename FT::t_arg a) { 
    return f(a);
   }
};


void mydeleter(int*);
#define FUNCTOR(F) Functor<decltype(F),&F>
Run Code Online (Sandbox Code Playgroud)

或者充分利用 C++11 的力量

template <typename F, F* f>
struct Functor
{
  template<typename... A>
  auto operator()(A&&... a) -> decltype(f(std::forward<A>(a)...)) {
    return f(std::forward<A>(a)...);
   }
};

#define FUNCTOR(F) Functor<decltype(F),&F>
Run Code Online (Sandbox Code Playgroud)