How to implement generic callbacks in C++

て烟熏妆下的殇ゞ 提交于 2019-12-18 12:48:15

问题


Forgive my ignorance in asking this basic question but I've become so used to using Python where this sort of thing is trivial that I've completely forgotten how I would attempt this in C++.

I want to be able to pass a callback to a function that performs a slow process in the background, and have it called later when the process is complete. This callback could be a free function, a static function, or a member function. I'd also like to be able to inject some arbitrary arguments in there for context. (ie. Implementing a very poor man's coroutine, in a way.) On top of that, this function will always take a std::string, which is the output of the process. I don't mind if the position of this argument in the final callback parameter list is fixed.

I get the feeling that the answer will involve boost::bind and boost::function but I can't work out the precise invocations that would be necessary in order to create arbitrary callables (while currying them to just take a single string), store them in the background process, and invoke the callable correctly with the string parameter.


回答1:


The callback should be stored as a boost::function<void, std::string>. Then you can use boost::bind to "convert" any other function signature to such an object, by binding the other parameters.

Example

I've not tried to compile this, but it should show the general idea anyways

void DoLongOperation(boost::function<void, const std::string&> callback)
{
  std::string result = DoSomeLengthyStuff();
  callback(result);
}


void CompleteRoutine1(const std::string&);
void CompleteRoutine2(int param, const std::string&);

// Calling examples
DoLongOperation(&CompleteRoutine1); // Matches directly
DoLongOperation(boost::bind(&CompleteRoutine2, 7, _1)); // int parameter is bound to constant.

// This one is thanks to David Rodríguez comment below, but reformatted here:
struct S 
{ 
  void f( std::string const & );
};

int main() 
{ 
  S s;
  DoLongOperation( boost::bind( &S::f, &s, _1 ) ); 
}



回答2:


Sounds like you want to use the Observer pattern.




回答3:


The easiest way:

class Callback
{
public:
  virtual ~Callback() {}
  virtual Callback* clone() const = 0;

  // Better to wrap the call (logging, try/catch, etc)
  void execute(const std::string& result) { this->executeImpl(result); }

protected:
  // Don't make sense to have them public
  Callback() {}
  Callback(const Callback&) {}
  Callback& operator=(const Callback&) { return *this; }

private:
  virtual void executeImpl(const std::string& result) = 0;
};

// Example
class Example: public Callback
{
public:
  Example(int a, int b): Callback(), mA(a), mB(b) {}
  virtual Example* clone() const { return new Example(*this); }

private:
  virtual void executeImpl(const std::string& result) {}

  int mA;
  int mB;
};

And then, you can pass the callback class (by pointer / reference) to the process. The class has a state, as required, and may be copied if necessary (if not, drop the clone).



来源:https://stackoverflow.com/questions/2471529/how-to-implement-generic-callbacks-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!