2014-12-13 43 views
0

我有以下類:使用回調作爲參數

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

    void timer(int); 
    //... 

private: 
    //... 
}; 

我的功能定時器(int值)是我在glutTimerFunc(使用回調),功能計時器內(int值),我需要再次使用功能定時器,如下所示:

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

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

我該怎麼做,而不使用靜態功能?

+2

你不能;谷歌愚蠢的方式,它不會添加一個'void * user'到它的回調函數中。 – 2014-12-13 13:07:07

+0

您可以使用lambda來包裝函數調用。通過這種方式,您可以將glut傳遞給非類方法,但您仍然在調用您的類方法。 – Ben 2014-12-13 13:07:58

+0

在C中,如果回調是'class'成員函數,那麼在C++中是可能的,那麼它不是一件容易的事情。首先'void timer(int)'必須是'static',然後你需要像'&Timer :: timer'那樣傳遞它。 – 2014-12-13 13:08:43

回答

0

你需要一個全球性的調度,輪流在int傳遞給glutTimerFunc成C++回調(成員函數,λ,等等)

像這樣

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