代码之家  ›  专栏  ›  技术社区  ›  rkellerm

什么是公开回调API—C++的最好方法

  •  1
  • rkellerm  · 技术社区  · 15 年前

    我有一个C++库,它应该将一些系统资源调用暴露为链接应用程序的回调。例如:接口应用程序(使用这个库)可以发送socket管理回调函数send、receive、open、close等,库将使用这个实现来代替库的实现。 (这种方式使应用程序能够自行管理套接字,这可能很有用)。 这个库还必须公开更多的回调,例如,密码验证,所以我想知道是否有一个首选方法在一个api中公开回调发送选项。 类似于:

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

    然后在我的库中,我将根据functioncallbacktype参数将回调分配给适当的函数指针。

    有没有什么方法可以用一种通用的方式来实现它,以适应任何函数原型和任何附加参数?

    你的帮助将不胜感激… 谢谢!

    4 回复  |  直到 15 年前
        1
  •  3
  •   Evan Teran    15 年前

    为什么不让它接受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,它基本上实现了bind在hood下的功能,它使用结构来存储多态性所需的所有信息和继承…很快就一团糟了。我不推荐,但会有用的。你也可以通过强迫 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));
    }
    
        2
  •  1
  •   JoeG    15 年前

    如果您不想去寻找任何可用的C++选项,则STD::Tr1:::函数、函子、多态与公共基类等。

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

    int AddCallbackFunc (int type, int(*callback)(void*), void* callbackData)
    
        3
  •  1
  •   Matthieu M.    15 年前

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

    其思想是采用任何类型并将其包装成具有已知接口的对象。

    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`.
    }
    

    我让你来绑定参数,没有库的方法是创建一个函子。

        4
  •  0
  •   marijne    15 年前

    听起来你在找 Functor . 基本上是每种回调类型的类,参数是数据成员 operator() 调用功能。