Как реализовать общие обратные вызовы в С++
Простите мое невежество в задании этого базового вопроса, но я настолько привык к использованию Python, что такого рода вещи тривиальны, что я полностью забыл, как я попытаюсь это сделать на С++.
Я хочу иметь возможность передать обратный вызов функции, которая выполняет медленный процесс в фоновом режиме, и вызывать ее позже, когда процесс завершен. Этот обратный вызов может быть свободной функцией, статической функцией или функцией-членом. Я также хотел бы иметь возможность вводить какие-либо произвольные аргументы там для контекста. (т.е. в какой-то мере реализует очень плохой man coroutine.) Кроме того, эта функция всегда будет принимать std::string, который является результатом процесса. Я не возражаю, если позиция этого аргумента в последнем списке параметров обратного вызова исправлена.
У меня возникает ощущение, что ответ будет включать boost:: bind и boost:: function, но я не могу выработать точные вызовы, которые необходимы для создания произвольных вызываемых вызовов (в то время как они просто берут один string), сохраните их в фоновом процессе и вызовите правильно вызываемый с параметром строки.
Ответы
Ответ 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 ) );
}
Ответ 2
Похоже, вы хотите использовать шаблон наблюдателя.
Ответ 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;
};
И затем вы можете передать класс обратного вызова (по указателю/ссылке) в процесс. Класс имеет состояние, если требуется, и при необходимости может быть скопирован (если нет, отбросить клон).