1

我试图揭露

typedef std::function<bool (int)> Filter;

这是一部分

#include <functional>

这样用户就可以创建过滤器并将其传递给我的组件进行处理。该要求要求不能在模板化函数中完成处理。

我知道在接口上使用 STL 不是一个好习惯,因为 Filter 类型的大小取决于 STL 实现。除了原始函数指针模板函数接收的函子之外,我还有哪些替代选项。

4

3 回答 3

2

大小在这里不是很重要,但是如果有人使用您的库的人使用不同的 STL 实现,那么您是对的,那么它将无法使用您的代码,那么另一种选择是什么?我将为此使用一个接口(纯虚拟类):

struct MyCallback {
    virtual bool filter( int ) = 0;
};
class MyImplementation {
public:
    ...
    void set_callbacks( MyCallback* );
};

使用这种架构,您可以让您的用户使用 C++ 的强大功能,同时您不依赖 STL!

于 2012-10-12T07:21:55.373 回答
1

C 风格的回调接口通常通过传递两个值来完成——一个函数指针和一个用户数据指针。如果你愿意,你可以把它包装在一个结构中。

因此,如果您希望您的 dll 接口保持 C 风格,请提供一种将 a 包装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如果将谓词传递给返回后不再使用它的算法,则惰性会得到回报。只有当过滤器被无限期注册时,你才需要一个完整的机制来管理生命周期。

于 2012-10-12T08:31:14.807 回答
1

您可以将函数指针作为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);
于 2012-10-12T06:24:10.297 回答