首页 文章

使用回调作为参数

提问于
浏览
0

我有以下课程:

class Timer
{
public:
    Timer(){};
    ~Timer(){};

    void timer(int);
    //...

private:
    //...
};

我的函数timer(int value)是我在glutTimerFunc()中使用的回调,在函数timer(int value)里面我需要再次使用函数timer,如下所示:

void Timer::timer(int value)
{
    //...

    glutTimerFunc(state->getTimer(), this->timer, 0);
}

如何在不使用静态功能的情况下完成?

1 回答

  • 0

    你需要一个全局调度程序,将传递给 glutTimerFuncint 转换为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;
    }
    

相关问题