C ++模板函数类型推导

时间:2013-11-08 05:10:40

标签: c++ templates c++11

我有这段代码:

template <typename T, void (*f)(T*)>
class callfn
{
  public:
  void operator()(T* obj) const
  {
    f(obj);
  }
};

void call(int* foo) {}

void test()
{
  callfn<int, call> fun;
  fun(1);
}

哪种方法可以正常工作。然而,callfn类型在所有地方使用,我更喜欢我可以这样称呼它

callfn<call> fun;

而不修改call的类型是否可以安排callfn模板/模板,使其可以从{{T类型中推导出f类型1}}?

2 个答案:

答案 0 :(得分:2)

aaronmanpost之上添加。虽然你不能单独使用模板类,但有一些帮助程序,包括宏,它可能是:

template <typename T>
T deduce(void(*)(T*));

#define CALLFN(f) callfn<decltype(deduce(f)), f> 

使用示例:

CALLFN(call) fun; // instead of 'callfn<call> fun;' as asked

然而,从OP的评论中,这只是一个问题,没有这一部分的解决方案似乎更简单。

如果我理解正确,您希望使用自定义函数删除器std::unique_ptr(类型为T)为特定类型f创建void (*)(T*)但是您不要不希望在std::unique_ptr中携带函数指针的开销。例如,考虑:

class MObj { /* ... */ };
void mfree(MObj*) { /* ... */ }

正如OP的评论所说,我们通常有

std::unique_ptr<MObj, void(*)(MObj*)> p1(nullptr, mfree);
assert(sizeof(p1) == sizeof(MObj*) * 2);

但使用callfn我们可以节省空间:

std::unique_ptr<MObj, callfn<MObj, mfree>> p2;
assert(sizeof(p2) == sizeof(MObj*));

我认为上述解决方案唯一的烦恼是需要两次输入callfnMObj。那么,这个怎么样:

template <typename T, void (*f)(T*)>
using light_unique_ptr = std::unique_ptr<T, callfn<T, f>>;

light_unique_ptr<MObj, mfree> p3; // 1
assert(sizeof(p3) == sizeof(MObj*));

我也明白(也许我错了)意图有更短的东西,比如

lighter_unique_ptr<mfree> p4; // 2
assert(sizeof(p4) == sizeof(MObj*));

并让编译器从mfree中推导出指向对象的类型。正如我所指出的,这可以用宏来完成,但我认为这不是一件好事,原因有两个:

  1. 如果我们对mfree(例如void mfree(MObj*)void mfree(Foo*))有不同的重载,则它不起作用。
  2. 用户通常希望在其实例化中看到std::unique_ptr的尖头类型,并且(最终)看到它的删除者。上面的第1行确实显示了类型(MObj),但第2行没有。没有看到类型可能会让一些人感到困惑。
  3. 我同意上面的第二点是有争议的(类似于 should-I-use-auto 辩论)。

答案 1 :(得分:1)

不需要知道结构或类的args只有函数在c ++中有模板类型推导。

论文n3602似乎解决了这个问题,所以看来你并不是唯一一个发现这种烦人的人(我也是)。我不知道它是否会被收录,但论文至少意味着其他人正在考虑它。 n6301将能够消除非类型模板参数的冗余类型名称。

另一件事(也在c ++ 14中)是make_unique,它将在下一个标准中。编写自己也可能相对容易。

正如我在评论中指出的那样,目前还不清楚你究竟想要实现什么,如果必须写出额外的类型实际上是一个障碍。

由于您在评论中明确表示需要这样做才能为unique_ptr做一个删除操作我不确定是什么问题。

std::unique_ptr<int,void(*)(int*)> ptr(int_ptr,deleter);