简体   繁体   English

C ++回调—如何解耦回调类型

[英]C++ Callback — How to decouple the call back type

For example, in the following pseudo code, Class B need to call A::Action() through B::m_cb member. 例如,在下面的伪代码中,类B需要通过B :: m_cb成员调用A :: Action()。

The objective is, how to make a general, non-template Callback class, so "B" does not have to be a template, and the "CallBack" can hold any kind of function signature. 目的是如何创建一个通用的非模板Callback类,因此“ B”不必是模板,并且“ CallBack”可以保存任何类型的函数签名。

I ever use such code before, but now I can not find that implementation. 我曾经使用过这样的代码,但现在找不到该实现。 All I remember is: 我只记得:
- the "CallBack" itself is not a template, but it contains member template -“ CallBack”本身不是模板,但包含成员模板
- the helper function template make_callback will instantiate CallBack object -辅助函数模板make_callback将实例化CallBack对象

Can anyone give a poiinter? 谁能给一个poiinter?

Class A
{
public:
   void Action(){//...};
};

class CallBack
{
   //...
   // CallBack it self it is a NOT a template
   // It can wrap member template though
};

class B
{
public:
   void SetCallback(CallBack to){
      m_cb = to;
   }
   void do_something()
   {
      //...
      m_cb.Execute();
      //...
   }

private:
   CallBack m_cb;

};

int main()
{
   A obj1;
   CallBack cb = make_callback(&obj1, &A::Action);
   B obj2;
   obj2.SetCallback(cb);
   //....
   obj2.do_something();
}

Here is the sample code I got from this same website. 这是我从同一网站获得的示例代码。 I tried to improved it a little bit, so it can tolerate arbitrary call back function's return type. 我试图对其进行一些改进,以便它可以容忍任意回调函数的返回类型。 But it still can not handle arbitrary number of arguments, like in line 18. Also, , T is the pointer to member function, which should be depend on C. I don't know how to enforce this. 但是它仍然不能像第18行那样处理任意数量的参数。此外,T是指向成员函数的指针,该成员函数应取决于C。我不知道如何执行此操作。

#include <iostream>
#include <memory>

// INTERNAL CLASSES

class CallbackSpecBase
{
  public:
    virtual ~CallbackSpecBase() {}
    virtual void operator()(...) const = 0;
};

template<class C, class T>
class CallbackSpec : public CallbackSpecBase
{
  public:
    CallbackSpec(C& o, T m) : obj(o), method(m) {}
/*line 18*/    void operator()(...) const { (&obj->*method)(); } // how to pass "..." into method(...)

  private:
    C& obj;
    T method;
};

// PUBLIC API

class Callback
{
  public:
    Callback() {}

    void operator()() { (*spec)(); }

    template<class C, class T>
      void set(C& o, T m) { spec.reset(new CallbackSpec<C, T>(o, m)); }

  private:
    std::auto_ptr<CallbackSpecBase> spec;
};

// TEST CODE

class Test
{
  public:
    void foo() { std::cout << "Working" << std::endl; }
    void bar() { std::cout << "Like a charm" << std::endl; }
};

int main()
{
  Test t;
  Callback c;
  c.set(t, &Test::foo);
  c();
  c.set(t, &Test::bar);
  c();
}

What you're looking for is std::function (C++0x) / boost::function . 您正在寻找的是std::function (C ++ 0x)/ boost::function These use type-erasure to make functions act like first-class objects. 它们使用类型擦除来使函数像一流的对象一样工作。 You can do something like this: 您可以执行以下操作:

class A
{
public:
    void Action() {//...};
};

class B
{
public:
    template <typename Func>
    void SetCallback(Func func) {
        m_cb = func;
    }

    void do_something() {
        m_cb(); // whatever function
    }

private:
    std::function<void()> m_cb; // anything callable with no arguments
};

int main()
{
    A obj1;
    B obj2;

    obj2.SetCallback(make_callback(&obj1, &A::Action));
    // or:
    obj2.SetCallback(std::bind(&obj1, &A::Action)); // or boost::bind

    obj2.do_something();
}

I have implemented a callback mechanism based on this article: 我已经根据本文实现了一种回调机制:

http://www.codeproject.com/KB/cpp/CPPCallback.aspx http://www.codeproject.com/KB/cpp/CPPCallback.aspx

With that implementation you can either use global functions , static member functions or non-static member functions as callbacks. 通过该实现,您可以将全局函数静态成员函数 或非静态成员函数用作回调。

The article describes how to create delegate objects as functors for all of these types. 本文介绍了如何将委托对象创建为所有这些类型的仿函数。 Your class B could have a delegate object as member and a method for registering a callback function and a method for calling it. 您的class B可以具有一个委托对象作为成员,以及一个用于注册回调函数的方法和用于对其进行调用的方法。 Neither class B nor your callback functions have to be templated! class B和您的回调函数都不必模板化! The delegate objects contain an object pointer in case a non-static member function is used as callback and a pointer to a templated static wrapper function. 如果将非静态成员函数用作回调,则委托对象包含一个对象指针,以及指向模板化静态包装器函数的指针。 In this wrapper function the function pointer to your callback function is stored. 在该包装函数中,存储了指向回调函数的函数指针。 It is either invoked directly or before bound to the passed object pointer. 它可以直接调用,也可以在绑定到传递的对象指针之前调用。

class B
{
  public:
    void SetCallback(CDelegate f_Delegate)
    {
      m_Delegate = f_Delegate;
    }
    static void do_something()
    {
      //...
      m_Delegate();
      //...
    }

  private:
    static CDelegate m_Delegate;
};

Update: 更新:

The mechanism is also described here: 5 years later, is there something better than the "Fastest Possible C++ Delegates"? 该机制的描述如下: 5年后,还有什么比“最快的C ++委托”更好的了吗?

This doesn't really answer your question, because a callback has to be a template, unless you want to pass a parameter through void* (which is totally crazy idea in my opinion). 这实际上并不能回答您的问题,因为回调必须是模板,除非您想通过void*传递参数(在我看来,这完全是疯狂的主意)。

I asked a similar question : What is wrong with this variadic templates example? 我问了一个类似的问题: 这个可变参数模板示例有什么问题?

One of answers gave a complete solution : 答案之一给出了一个完整的解决方案:

#include <memory>

template< typename R, typename ... Args >
class CallbackBase
{
public:
    typedef std::shared_ptr< CallbackBase< R, Args... > >
            CallbackPtr;

    virtual ~CallbackBase()
    {
    }
    virtual R Call(  Args ... args) = 0;
};

template< typename R, typename ... Args >
class FunctionCallback : public CallbackBase< R, Args... >
{
public:
    typedef R (*funccb)(Args...);

    FunctionCallback( funccb  cb_ ) : 
        CallbackBase< R, Args... >(),
        cb( cb_ )
    {
    }
    virtual ~FunctionCallback()
    {
    }
    virtual R Call(Args... args)
    {
      return cb( args... );
    }
private:
  funccb cb;
};

template < typename R, typename ...Args >
typename CallbackBase< R, Args... >::CallbackPtr
    MakeCallback( R (*cb)(Args...)  )
{
    typename CallbackBase< R, Args... >::CallbackPtr
        p( new FunctionCallback< R, Args... >( cb )
);
    return p;
}

bool Foo_1args( const int & t)
{
    return true;
}
int main()
{
    auto cbObj = MakeCallback( & Foo_1args );
}

Hope it helps. 希望能帮助到你。 If you hate templates, you can always use a typedef. 如果您讨厌模板,则始终可以使用typedef。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM