Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Pass const std::function<void()> as parameter in SDL_AddTimer as void*

I am trying to pass a const std::function<void()> & as void * to SDL_AddTimer, which its 3rd parameter is void *.

I tried with reinterpret_cast

SDL_AddTimer(interval, wrapper, reinterpret_cast<void *>(const_cast<std::function<void()> *>(fn)));

But on my wrapper, it crashes

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

uint32_t wrapper(uint32_t interval, void *param) {
  auto fn = static_cast<std::function<void()> *>(param);
  (*fn)(); // crashes here.
  return interval;
}

What I am doing wrong?

EDIT: Usage:

timer t;
t.set(1000, []() {
  std::cout << "Hello, world!" << std::endl;
});

>Solution :

You can’t cast a std::function into a void* like you are doing (you can’t even cast a reference into a pointer the way you are doing).

But, you can pass the address of the std::function object itself. That is what your wrapper is expecting anyway, eg:

auto &fn_ref = const_cast<std::function<void()> &>(fn); // note & not *
SDL_AddTimer(interval, wrapper, &fn_ref);
uint32_t wrapper(uint32_t interval, void *param) {
  auto fn = static_cast<std::function<void()> *>(param);
  (*fn)();
  return interval;
}

Just make sure the std::function object stays alive while the SDL timer is running. However, based on your usage example, it appears the std::function object may go out of scope before the timer ever has a chance to call it. So, you will have to save the std::function object somewhere until the timer stops running, eg:

class timer {
    SDL_TimerID timerID = 0;
    std::function<void()> timerFunc;

public:
    timer() = default;
    ~timer();

    void set(uint32_t interval, const std::function<void()> &fn);
    void stop();
};
uint32_t wrapper(uint32_t interval, void *param) {
  auto fn = static_cast<std::function<void()> *>(param);
  (*fn)();
  return interval;
}

timer::~timer() {
    stop();
}

void timer::set(uint32_t interval, const std::function<void()> &fn) {
    stop();
    timerFunc = fn;
    timerID = SDL_AddTimer(interval, wrapper, &timerFunc);
}

void timer::stop() {
    if (timerID != 0) {
        SDL_RemoveTimer(timerID);
        timerID = 0;
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading