0

I have a simple timer, which i want to execute my function after a fixed time.

the code is:

#include <thread>
typedef void (*callback)();
class timer {
 public:
   virtual ~timer() {
     t_.join();
   }
   void start(int sec, callback f) {
     if (t_.joinable()) t_.join();
     t_ = std::thread([sec, &f]() {sleep(sec); f();});
   }
  std::thread t_;
};

void test () {
  printf("here called\n");
}
int main() {
  timer t;
  t.start(3, test);  // TODO: test is ok, but it wont work
  // if test is a class member function, or it have parameters.
  while (1);
}

it's ok to use if my function is a global, non-parameters function.

but when i use class member funtion(not static), i think it wont work.

So, Can you help on this if i want my function have parmaters and may be a class member function?

cppdev
  • 3
  • 3
  • 1
    You can use [std::bind](https://en.cppreference.com/w/cpp/utility/functional/bind) to bundle a multi-argument function together with some values for the arguments to create a callable suitable for your `timer` class. – Nathan Pierson Aug 05 '21 at 02:30
  • Take a look at the Timer class [Ruk just posted here.](https://stackoverflow.com/a/68659901/4581301) It's significantly simpler and more stable than what you're doing here with a dynamically allocated `thread` and `detach`. As for your problem, look into [lambda expressions](https://en.cppreference.com/w/cpp/language/lambda) and [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function). – user4581301 Aug 05 '21 at 02:40
  • @user4581301 thx – cppdev Aug 05 '21 at 02:54
  • With `[sec, &f]`, you capture local variable `f` in something which outlive local scope, so have dangling pointer. – Jarod42 Aug 05 '21 at 08:19

1 Answers1

1

We may use a start function with a template argument to replace the function pointer argument

#include <chrono>
#include <functional>
#include <iostream>
#include <thread>
class timer {
 public:
  virtual ~timer() { t_.join(); }
  template <typename Fn>
  void start(std::chrono::seconds sec, Fn&& f) {
    t_ = std::thread([sec, f = std::move(f)]() {
      std::this_thread::sleep_for(sec);
      f();
    });
  }
  std::thread t_;
};

void test() { printf("here called\n"); }

class A {
 public:
  void test(int arg) {
    std::cout << "a member function with arg:" << arg << '\n';
  }
};

int main() {
  timer t;
  auto sec(std::chrono::seconds(1));
  t.start(sec, test);

  timer t1;
  t1.start(sec, []() { std::cout << "lambda\n"; });

  timer t2;
  auto a_ptr = std::make_shared<A>();
  t2.start(sec, std::bind(&A::test, a_ptr, 1));

  timer t3;
  t3.start(sec, [] {
    A a;
    a.test(1);
  });

  return 0;
}

Online demo

prehistoricpenguin
  • 6,130
  • 3
  • 25
  • 42