将回调函数打包到模板化类中

时间:2017-07-11 00:23:19

标签: c++ templates

我正在尝试创建一个回调函数结构,我可以放置一个泛型函数和它将接收的所有参数,以便在执行期间我可以调用它。

对我而言,它看起来像这样:

template <typename T, typename... targs>
class CallbackFunction {
private:
    targs... args;
    std::function<T(targs...)> fun;

public:
    CallbackFunction(std::function<T(targs...)> fun, targs... args) : fun(fun), args(args) {}

    T call () {
        return this->fun(this->args);
    }
};

所以我可以这样做:

CallbackFunction cb = CallbackFunction(printf, "Hello World!\n");

cb.call();

我知道这样做有两个问题:

1-你无法存储targs ... args。编译器说data member type contains unexpanded parameter pack 'targs'

2-您无法按原样将args发送到该功能。你需要以某种方式解压缩它。编译器说expression contains unexpanded parameter pack 'args'

这样做的正确方法是什么?

1 个答案:

答案 0 :(得分:2)

template<class T>
using CallbackFunction=std::function<T()>;

CallbackFunction<void> cb = []{printf("Hello World!\n");};

cb();

类型T必须是类型的一部分,因此除非C ++ 17必须列出至少它。

targs...只是一个内部细节。 std::function会在签名上键入擦除,并可以处理存储任何targs...或其他状态的集合。

可以调用并返回T并存储某些状态的对象是std::function<T()>。剩下的就是渣滓。

如果你真的必须

template <typename T>
class CallbackFunction {
  std::function<T()> fun;

public:
  template<class...targs>
  CallbackFunction(std::function<T(targs...)> fun, targs... args) : fun([=]{ return fun(args...); }){}
  T call() const {
    return fun();
  }
};

使用移动语义对此进行优化是一项更多的工作。查找std::apply的实现:

  template<class...targs>
  CallbackFunction(std::function<T(targs...)> fun, targs... args) : fun(
    [fun=std::move(fun), args=std::make_tuple(std::move(args)...)]()->decltype(auto){
      return std::apply(fun,args);
    }
  ){}