首页 > 解决方案 > 如何在不使用 C++ 创建函数对象的情况下将函数指针作为模板值参数传递?

问题描述

我在这里看到了这个问题的许多变体,但我仍然觉得我的具体情况有所不同。

我的目标是包装一个如下所示的 C API:

TF_Buffer* buf = TF_AllocateBuffer();
// ...
TF_DeleteBuffer(buf);

由于我有很多这样的对象,我很想创建一个名为的泛型类型handle,它可以保存给定的指针并在销毁时调用适当的释放器。我想象的用例是

class buffer : public handle<TF_Buffer, TF_DeleteBuffer> {
public:
  buffer(TF_Buffer* b): handle(b) {}
}

不幸的是,我无法让它工作,因为TF_DeleteBuffer它是一个简单的函数(类型void TF_DeleteBuffer(TF_Buffer*))。我确实设法解决了为函数创建函数对象的问题,因此以下方法确实有效

template<typename Obj, typename Deleter>
class handle {
public:
  Obj* obj;

  handle(Obj* o): obj(o) {};
  ~handle() { if (obj) Deleter()(obj); }
};

struct buffer_deleter {
  void operator()(TF_Buffer* b) { TF_DeleteBuffer(b); }
};

class buffer : public handle<TF_Buffer, buffer_deleter> {
public:
  buffer(TF_Buffer* b): handle(b) {}
}

但是buffer_deleter为了这个目的而定义类感觉很脏。我想像这样的东西应该可以工作(有或没有std::function

template<typename Obj, std::function<void(Obj*)> Deleter>
class handle {
  // ...
}

但我找不到让编译器满意的方法。据我了解,这有点类似于std::unique_ptr接受删除器类型对象,std::shared_ptr而接受删除器函数指针并将其存储在共享对象中。我不介意显式存储指针(并使用额外的内存),但同时,鉴于我将创建很多这些类型,我想有一些方法让它在语法上很好。我真的不想将删除器指针传递给正在创建的对象的每个实例,这就是我试图将它隐藏在模板中的原因。

标签: c++templatesfunction-pointers

解决方案


您可以将非类型模板参数定义为函数指针。

template<typename Obj, void(*Deleter)(Obj*)>
class handle {
public:
  Obj* obj;

  handle(Obj* o): obj(o) {};
  ~handle() { if (obj) Deleter(obj); }
};

并像使用它一样

class buffer : public handle<TF_Buffer, &TF_DeleteBuffer> {
  ...
};

推荐阅读