我试图揭穿
typedef std::function<bool (int)> Filter;
这是一部分
#include <functional>
使用户可以创buildfilter并将其传递到我的组件进行处理。 该要求要求处理不能在模板化的function中完成。
我知道在接口上使用STL并不是一个好的做法,因为Filtertypes的大小是依赖于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
是一个传递给一个算法的谓词,那么返回后就不会再使用它了。 只有当过滤器无限注册时,你需要一个完整的机制来管理生命周期。