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

Packing a callback function into a templated class

本文关键字:回调 函数      更新时间:2023-10-16

我正在尝试创建一个回调函数结构,我可以放置一个泛型函数及其将接收的所有参数,以便在执行过程中的任何时候都可以调用它。

对我来说,它看起来像这样:

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-你不能存储塔格...参数。编译器说data member type contains unexpanded parameter pack 'targs'

2-您不能按原样将参数发送到函数。你需要以某种方式解开它。编译器说expression contains unexpanded parameter pack 'args'

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

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);
}
){}