使用回调作为参数

use a callback as a parameter

本文关键字:参数 回调      更新时间:2023-10-16

我有以下类:

class Timer
{
public:
    Timer(){};
    ~Timer(){};
    void timer(int);
    //...
private:
    //...
};

我的函数计时器(int 值)是我在 glutTimerFunc() 中使用的回调,在函数计时器(int 值)中我需要再次使用函数计时器,如下所示:

void Timer::timer(int value)
{
    //...
    glutTimerFunc(state->getTimer(), this->timer, 0);
}

如何在不使用静态函数的情况下做到这一点?

您需要一个全局调度程序,将传递给glutTimerFunc int转换为 C++ 回调(成员函数、lambda 等)

像这样的东西

struct timer_dispatch
{
  using callback_t = std::function<void()>;
  int start_timer(int msecs, callback_t callback) {
    std::unique_lock<std::mutex> lock(_mutex);
    int ident = _next_id++;
    _callbacks.emplace(ident, std::move(callback));
    glutTimerFunc(msecs, &timer_dispatch::dispatch_timer, ident);
    return ident;
  }
  // implement similar function for stop timer - don't forget the mutex
  void stop_timer(int ident) {
    std::unique_lock<std::mutex> lock(_mutex);
    _callbacks.erase(ident);
  }
  static timer_dispatch& instance() {
    static timer_dispatch _;
    return _;
  }  
private:
  // private constructor ensures use via the instance() static method;
  timer_dispatch() = default; 
  static void dispatch_timer(int ident) {
    auto self = instance();
    std::unique_lock<std::mutex> lock(self._mutex);
    auto it = self._callbacks.find(ident);
    if (it != self._callbacks.end()) {
      auto my_copy = std::move(it->second);
      self._callbacks.erase(it);
      lock.unlock();
      my_copy();
    }
  }
private:      
  std::unordered_map<int, callback_t> _callbacks;
  std::mutex _mutex;
  int _next_id = 0;
};

现在像这样使用:

// start my timer:
void myclass::start_alien() {
  ...
  _alien_timer_id = timer_dispatch::instance().start_timer(100, std::bind(&myclass::on_alien_timeout, this);
  ...
}
void myclass::on_alien_timeout() {
  // make alien do something, possibly restart a timer...
  _alien_timer_id = timer_dispatch::instance().start_timer(100, std::bind(&myclass::on_alien_timeout, this);
}
void myclass::on_alien_killed() {
  timer_dispatch::instance().stop_timer(_alien_timer_id);
  _alien_timer_id = -1;
}