Подтвердить что ты не робот

Как реализовать общие обратные вызовы в С++

Простите мое невежество в задании этого базового вопроса, но я настолько привык к использованию Python, что такого рода вещи тривиальны, что я полностью забыл, как я попытаюсь это сделать на С++.

Я хочу иметь возможность передать обратный вызов функции, которая выполняет медленный процесс в фоновом режиме, и вызывать ее позже, когда процесс завершен. Этот обратный вызов может быть свободной функцией, статической функцией или функцией-членом. Я также хотел бы иметь возможность вводить какие-либо произвольные аргументы там для контекста. (т.е. в какой-то мере реализует очень плохой man coroutine.) Кроме того, эта функция всегда будет принимать std::string, который является результатом процесса. Я не возражаю, если позиция этого аргумента в последнем списке параметров обратного вызова исправлена.

У меня возникает ощущение, что ответ будет включать boost:: bind и boost:: function, но я не могу выработать точные вызовы, которые необходимы для создания произвольных вызываемых вызовов (в то время как они просто берут один string), сохраните их в фоновом процессе и вызовите правильно вызываемый с параметром строки.

4b9b3361

Ответ 1

Обратный вызов должен быть сохранен как boost::function<void, std::string>. Затем вы можете использовать boost::bind для "преобразования" любой другой сигнатуры функции в такой объект, связывая другие параметры.

Пример

Я не пытался скомпилировать это, но он должен показывать общую идею в любом случае

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

Ответ 3

Самый простой способ:

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

И затем вы можете передать класс обратного вызова (по указателю/ссылке) в процесс. Класс имеет состояние, если требуется, и при необходимости может быть скопирован (если нет, отбросить клон).