按值</b​​ool>传递std :: function <bool(int)=“”>

时间:2012-10-12 06:18:03

标签: c++ windows macos

我试图揭露

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

的一部分
#include <functional>

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

据我所知,在接口上使用STL不是一个好习惯,因为Filter类型的大小取决于STL实现。我的替代选项是原始函数指针,还是由模板化函数接收的仿函数。

3 个答案:

答案 0 :(得分:2)

这里的大小如果不是非常重要,但是如果某个使用你的库的人使用不同的STL实现,那么它是正确的,那么它将无法使用你的代码,那么还有什么选择呢?我将使用一个接口(纯虚拟类):

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

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

答案 1 :(得分: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);

答案 2 :(得分:1)

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是传递给返回后不再使用它的算法的谓词,则懒惰会得到回报。只有当过滤器无限期注册时,您才需要一个完整的机制来管理生命周期。