0

The following code starts a non-blocking timer that will launch the function myFunc after one second:

MyClass.h:

std::future<void> timer_future_;

MyClass.cpp:

timer_future_ = std::async(

        std::launch::async,
        [this] { QTimer::singleShot(1000,
                                    [this] {this->myFunc();}
                                    );
               }
    );

I would like to replace the lambda functions with std::functions. I have successfully replaced the second lambda as follows:

timer_future_ = std::async(

        std::launch::async,
        [this] { QTimer::singleShot(1000, 
                                    std::bind(&MyClass::myFunc, this)
                                    );
               }
    );

How can I now replace the first lambda with another std::bind() call?

Note that the function QTimer::singleShot is from the Qt libraries; its documentation is here. Its prototype is:

void QTimer::singleShot(int msec, Functor functor)

As per this question, the definition of the Functor type can be found in QObject.h. It says:

template <class FunctorT, class R, typename... Args> class Functor { /*...*/ }

After some research, I understand that the std::bind() that will replace the first lambda must take account of the following:

I have made several unsuccessful attempts, the last of which was:

timer_future_ = std::async(
        std::launch::async,
        std::bind( ( void(*) (int, Functor<const std::function<void(void)>,void>) )&QTimer::singleShot,
                  1000,
                  std::bind(&MyClass::myFunc, this)
                  )
);

For this code, the MSVC compiler returned the error message

error: C2059: syntax error: ')'

on the third line.

Why don’t I just use the lambdas which are already working? The answer is simply that trying to use std::bind() instead is teaching me more about the various features of the C++ language and how to use them.


EDIT: Code that implements Kuba Ober's answer:

QTimer::singleShot(1000, [this] {
    timer_future_ = std::async(
                std::launch::async,
                std::bind(&MyClass::myFunc, this)
                );
});
Everlearn
  • 63
  • 6

2 Answers2

0

Count opening and closing brackets and add a semicolon

Jens
  • 6,173
  • 2
  • 24
  • 43
  • Sorry, a typo has left the last bracket and semicolon outside the code block which shows my attempt. I have edited it. This typo was not in the code that I tried to compile. – Everlearn May 09 '18 at 19:32
0

The timer requires an event loop, and std::async will invoke it in a worker thread that doesn't have a running event loop. I question why would you ever want to do it?

If you want to run something in a worker thread after a delay, run the timer in a thread that has an event loop, and fire off the async action from that timer.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • Thank you, you are right. I was trying to run a timer without blocking the event loop. I should have put the `async()` call inside the `QTimer::singleShot()` call. I've added working code that follows this approach at the bottom of the question. – Everlearn May 10 '18 at 20:35