简体   繁体   English

如何在C ++中实现通用回调

[英]How to implement generic callbacks in C++

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++. 原谅我对这个基本问题的无知,但我已经习惯了使用Python,这种事情是微不足道的,我已经完全忘记了如何在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. (即,在某种程度上实现一个非常差的人的协程。)最重要的是,这个函数将始终采用std :: string,这是进程的输出。 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. 我觉得答案将涉及boost :: bind和boost :: function但是我无法确定为了创建任意的callables而需要的精确调用(同时将它们调整为只需要一个字符串),将它们存储在后台进程中,并使用string参数正确调用callable。

The callback should be stored as a boost::function<void, std::string> . 回调应该存储为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. 然后,您可以通过绑定其他参数,使用boost::bind将任何其他函数签名“转换”为此类对象。

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 ) ); 
}

听起来你想要使用Observer模式

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). 该类具有根据需要的状态,并且可以在必要时复制(如果不是,则删除克隆)。

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

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