公开回调API的最佳方法是什么 - C ++

时间:2010-04-27 15:42:11

标签: c++ api callback

我有一个C ++库,它应该将一些system \ resource调用作为来自链接应用程序的回调公开。例如:接口应用程序(使用该库)可以发送套接字管理回调函数 - 发送,接收,打开,关闭等,库将使用此实现代替库的实现。 (这种方式使应用程序能够自己管理套接字,可能很有用)。 这个库还需要公开更多的回调,比如密码验证,所以我想知道是否有一种首选方法可以在一个API中公开回调发送选项。 类似的东西:

int AddCallbackFunc (int functionCallbackType, <generic function prototype>, <generic way to pass some additional arguments>)

然后在我的库中,我将根据functionCallbackType参数将回调分配给相应的函数指针。

有没有办法以通用的方式实现它,它适合任何函数原型和任何其他参数?

您的帮助将不仅仅是... 谢谢!

4 个答案:

答案 0 :(得分:3)

为什么不接受0参数functor并让用户在注册之前使用boost::bind来构建参数?基本上是示例(调用而不是商店,但你明白了):

#include <tr1/functional>
#include <iostream>

void callback(const std::tr1::function<int()> &f) {
    f();
}

int x() {
    std::cout << "x" << std::endl;
    return 0;
}

int y(int n) {
    std::cout << "y = " << n << std::endl;
    return 0;
}

int main(int argc, char *argv[]) {
    callback(x);
    callback(std::tr1::bind(y, 5));
}

编辑:有一个选项B,它基本上实现了绑定所带来的结构,以存储所有需要的信息和多态性的继承...它变得一团糟。我不推荐它,但它会起作用。您还可以通过强制返回int类型来避免悲伤,但这只能为您节省一些时间。

#include <iostream>

struct func_base {
    virtual int operator()() = 0;
};

// make one of these for each arity function you want to support (boost does this up to 50 for you :-P
struct func0 : public func_base {
    typedef int (*fptr_t)();

    func0(fptr_t f) : fptr(f) {
    }

    virtual int operator()() { return fptr(); }

    fptr_t fptr;
};

// demonstrates an arity of 1, templated so it can take any type of parameter
template <class T1>
struct func1 : public func_base {
    typedef int (*fptr_t)(T1);

    func1(fptr_t f, T1 a) : fptr(f), a1(a) {
    }

    virtual int operator()() { return fptr(a1); }

    fptr_t fptr;
    T1 a1;
};

void callback(func_base *f) {
    (*f)();
}

int x() {
    std::cout << "x" << std::endl;
    return 0;
}

int y(int n) {
    std::cout << "y = " << n << std::endl;
    return 0;
}

int main(int argc, char *argv[]) {
    // NOTE: memory leak here...
    callback(new func0(x));
    callback(new func1<int>(y, 5));
}

答案 1 :(得分:1)

如果您不想使用任何可用的C ++选项; std :: tr1 :: function,functors,带有公共基类等的多态性,你可以使用C方法。

客户端将回调和指向其参数的指针作为void *传递,然后回调在调用时将void *转换为正确的类型。你需要在回调旁边存储void *,你需要非常小心对象的生命周期。

int AddCallbackFunc (int type, int(*callback)(void*), void* callbackData)

答案 2 :(得分:1)

可以使用模板和类型擦除的组合来完成。

我们的想法是采用任何类型并将其包装到具有已知接口的对象中。

class CallbackBase
{
public:
  virtual ~CallbackBase();

  virtual void execute();
};

template <class T>
class Callback: public CallbackBase
{
public:
  explicit Callback(T functor): mFunctor(functor) {}

  void execute() { mFunctor(); }

private:
  T mFunctor;
};

现在,我们可以把它包起来:

template <class Function>
int AddCallbackFunc (int functionCallbackType, Function f)
{
  std::auto_ptr<CallbackBase> c(new Callback<Function>(f));

  // do something with `c`.
}

我把它留给你来绑定参数,没有库的方法是创建一个仿函数。

答案 3 :(得分:0)

听起来你正在寻找一个Functor。基本上是每种类型回调的类,其中参数为数据成员,operator()用于调用功能。