我有一个接受回调类型的库
double *(double)
现在,我想传递几个在另一个参数上参数化的回调。更准确地说,我有一个带有签名的功能
double f(double, int)
现在我想写些类似的东西
for(int parameter: {...some values(known at compile time)...})
{
//register callback x mapsto f(x,parameter)
}
我无法将回调包装在lambda中,因为它将被捕获,因此它不能转换为函数指针。同样,据我了解,绑定对象无法转换为函数指针(尽管我不确定为什么),因此无法绑定参数。
有人知道该怎么做吗?
编辑:我想要一个使用编译器模板引擎为我生成这些功能的解决方案。 另外,如果这对您有帮助,我会使用c ++ 17,如果需要的话,我也愿意使用诸如boost hana之类的库。
答案 0 :(得分:0)
您需要一些存储空间来保持绑定值,除非您在编译时使用宏创建函数,否则原始函数指针无法做到这一点。 (或者在不久的将来使用反射+元类)在运行时无法执行。
您可以使用std::bind
,然后例如存储std::function
实例。
#include <vector>
#include <functional>
double function(double, int);
void register_all() {
using namespace std::placeholders;
// values to bind
std::vector<int> v = { 1, 4, 6, 8 };
// our callback registry
std::vector<std::function<double(double)>> funcs;
// registration
for (auto i : v) {
funcs.emplace_back(std::bind(function, _1, i));
}
//call
for (auto &f : funcs) {
f(1.0);
}
}
如果您不能将回调类型更改为std::function
或类似的方法,则唯一的方法是注册一个回调以进行进一步的调用。即
double my_callback(double d) {
for (int i : whatever) {
f(d, i);
}
}
// ... somewhere else
register_callback(my_callback);
旁注:
一个好的C回调API将允许传递void*
,可以通过它获得额外的特定于回调的信息,这些信息可以用于携带额外的数据。但是,简单函数指针对于其他任何东西都太受限制了。
编辑:
如果在编译时知道所有(潜在)值,则可以使用模板进行包装:
#include <vector>
double f(double d, int i);
template<int i>
double f_wrapper(double d) {
return f(d, i);
}
int main() {
std::vector<double(*)(double)> funcs;
funcs.push_back(&f_wrapper<0>);
funcs.push_back(&f_wrapper<1>);
funcs.push_back(&f_wrapper<2>);
//call
double r = .0;
for (auto &f : funcs) {
r += f(1.0);
}
}
具有更多可变参数模板魔术:
#include <vector>
double f(double d, int i);
template<int i>
double f_wrapper(double d) {
return f(d, i);
}
template<int... id>
void register_cbs(std::vector<double(*)(double)>& funcs) {
(funcs.push_back(&f_wrapper<id>), ...);
}
int main() {
// register
std::vector<double(*)(double)> funcs;
register_cbs<1,2,5,10>(funcs);
//call
double r = .0;
for (auto &f : funcs) {
r += f(1.0);
}
}
但是再次必须在编译时知道这些值。