1

I want to create a function like setInterval(func, delay, [arg1, arg2, ...]); of JavaScript.

void func(int t) {
    std::cout<<t<<std::endl;
}

void func(int i, char* t) {
    std::cout<<t<<std::endl;
}

class Timer {
public:
    void setInterval(auto function, int interval, ...args);
};

void Timer::setInterval(auto function, int interval, ...args) {
    while(1) {
        function(args);
        msleep(interval);
    }
}

int main() {
    Timer *t1 = new Timer;
    t1->setInterval(func, 1000, 2021);

    Timer *t2 = new Timer;
    t2->setInterval(func, 1000, 2, "hello");

    while (1) {

    }
    return 0;
}

But I don't know how to convert variadic arguments to Class member function. Can anyone help me? Thank you.

ssroreo
  • 127
  • 6

2 Answers2

2

You can do it by using template.

#include <iostream>
#include <thread>

class Timer 
{
public:
    template <typename T>
    void SetInterval(int interval, T t)
    {
        std::cout << t << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(interval));
    }

    template <typename T, typename... Types>
    void SetInterval(int interval, T t, Types... args)
    {
        SetInterval(interval, args...);
    }
};

int main() {
    Timer *t1 = new Timer;
    t1->SetInterval(1000, 2001);

    Timer *t2 = new Timer;
    t2->SetInterval(1000, 2, "hello");

    delete t1;
    delete t2;

    while (1) {

    }
    return 0;
}
secuman
  • 539
  • 4
  • 12
  • Better (for compile time) to avoid recursion and use folding expression: `(std::cout << args), ...); std::cout << std::endl; /*..*/` – Jarod42 Aug 10 '21 at 12:03
  • No, only when the last parameter of args, sleep works. – secuman Aug 10 '21 at 12:13
  • I know that the folding expression is available from C++17, I am using c+11, and, the second call in ssroreo's code, the last parameter is only printed. – secuman Aug 10 '21 at 12:16
  • There are tricks to mimic fold expressions in C++11 (as `const int dummy[] = {0, (f(ts), 0)...};`). – Jarod42 Aug 10 '21 at 12:25
  • Not sure it was not a OP's typo to print only the last parameter though ;-) – Jarod42 Aug 10 '21 at 12:27
  • In that case, it will be sufficient to use std::cout << t << ", "; before call SetInterval(interval, args...); in second template function. – secuman Aug 10 '21 at 12:32
0

I suggest

class Timer
{
public:

    void setInterval(std::function<void()> f, std::chrono::milliseconds interval)
    // template <typename F> void setInterval(F f, std::chrono::milliseconds interval)
    {
        while (true) {
            f();
            std::this_threas::sleep_for(interval);
        }
    }
};

With calls similar to:

using namespace std::chrono_literals;

Timer t1;
t1.setInterval([](){ func(2021);}, 1000ms);

Timer().setInterval([](){ func(2, "hello");}, 1000ms);
Jarod42
  • 203,559
  • 14
  • 181
  • 302