我试图揭露传递的std ::功能<bool (int)>通过值
typedef std::function<bool (int)> Filter;
是
#include <functional>
这样的一部分用户可以创建过滤器,并将其传递到我的处理组件。该要求要求处理不能在模板化功能中完成。
我知道在接口上使用STL并不是一种好的做法,因为Filter类型的大小是STL实现相关的。我的替代选项是什么,但对于原始函数指针或仿函数接收到仿函数。
我试图揭露传递的std ::功能<bool (int)>通过值
typedef std::function<bool (int)> Filter;
是
#include <functional>
这样的一部分用户可以创建过滤器,并将其传递到我的处理组件。该要求要求处理不能在模板化功能中完成。
我知道在接口上使用STL并不是一种好的做法,因为Filter类型的大小是STL实现相关的。我的替代选项是什么,但对于原始函数指针或仿函数接收到仿函数。
大小,如果不是真的很这里重要的,但你是对的,如果有人使用你的库使用不同的实现STL的,那么它将无法使用你的代码,所以有什么其他选择?我会用这个接口(纯虚类):
struct MyCallback {
virtual bool filter(int) = 0;
};
class MyImplementation {
public:
...
void set_callbacks(MyCallback*);
};
使用这种架构可以让你的用户使用的C++,并在同一时间的权力,你不依赖于STL!
您可以传递函数指针作为std::bind
的结果。例如:
typedef std::function<bool (int)> Filter;
bool Foo(int i)
{
return i == 0;
}
void BarCaller(Filter bar) //pass by value
{
bar(2);
}
Filter bar = std::bind(&Foo, std::placeholders::_1); //now you can pass bar wherever you want
BarCaller(bar);
C风格的回调接口通常通过传递两个值 - 一个函数指针和一个用户数据指针来完成。如果你愿意的话,你可以把它包装在一个结构体中。
所以,如果你想让你的dll界面保持C风格,请提供一种方法来包装std::function
。喜欢的东西:
bool c_style_callback(void *userdata, int n) {
return (*static_cast<const Filter*>(userdata))(n);
}
你可以提供一个头文件中的便利功能,即在调用的dll运行,并提供你真正想要的界面:
inline void register_callback(const Filter &filter) {
register_c_style_callback(c_style_callback, static_cast<void*>(&filter));
}
我已经懒的和这呼叫者有责任确保filter
只要注册回叫就保持有效。你可以通过动态分配它的副本来修复它,并且在回调被注销时添加代码来检索和释放它(再次,这个代码在调用DLL中运行)。如果取消注册是由调用者发起的,那么您需要某种代表注册回调的句柄。
如果Filter
是一个传递给算法的谓词,在返回后不会再使用它,那么懒惰就会带来回报。只有当过滤器无限注册时,您才需要整个机制来管理生命周期。
史蒂夫,我看到的唯一问题是丑陋的看起来 “void *” 我知道这是C风格的回调和无效*是面包和黄油。我希望有更优雅的东西。 +1的努力。谢谢。 – Ram
你的问题并不清楚,究竟是什么问题?什么都不行,你想做什么? – Xeo
“*我有什么替代选项,但是... *”您可以实现您自己的'std :: function'版本。另外,“*我明白,在接口上使用STL并不是一种好的做法,因为Filter类型的大小是STL实现的依赖。”为什么这一点至关重要?谁在乎'std :: function'有多大?由于对象的大小,您的代码不会失败。接口的唯一问题来自* dll *接口,其中C++基本上是禁止的。 –
@Nicol:有趣的是BigBoss不同意,并准备在界面中使用有限的C++。基本上,他愿意承担一个ABI,允许具有虚拟功能的班级,但不会规定整个标准库的布局。 –