Wait for a signal which carrying a specific argument
-
Suppose we want wait a signal (with arguments), and keep blocking until meet an incoming signal carrying some specific arg?
signals: triggered(int i)
QTimer timer; timer.setSingleShot(true); QEventLoop loop; connect( this, &MyClass::triggered, &loop, [&](int i) { // only 123 would stop the event loop, otherwise keep waiting if (i == 123) loop.quit(); } ); connect( &timer, &QTimer::timeout, &loop, &QEventLoop::quit ); timer.start(msTimeout); loop.exec(); if(timer.isActive()) qDebug("Got 123! It may not be carried by the first incoming signal."); else qDebug("timeout");
Is it possible to rewrite this into a reuseable header template? e.g.
waitForTimeout(QObject* sender, Func1 signal, Func2 predicate, int msec)
-
S SGaist moved this topic from Wiki Discussion on
-
Most likely not.
It is certainly possible to write a template
template <class Func1, class Func2> void waitForTimeout(QObject* sender, Func1 signal, Func2 predicate, int msec)
and call it withwaitForTimeout(this, &MyClass::triggered, [&](int i){...}, msTimeout);
.However, the predicate cannot reference the loop because it cannot capture it. Possibly there is a workaround that you could also provide an additional signal which will be connected to
loop.quit()
. This signal could be captured by your predicate lambda and thus emitted.Another approach could be to make it a class
waitForTimeout_t
. Then I would probably store the predicate as astd::function
. This would allow a 2-step approach with a constructor and member functions:waitForTimeout_t waiter(this, &MyClass::triggered, [&](int i) {}, msTimeout); // just a dummy lambda to get the type right for std::function waiter.setPrecidate([&](int i) { if(i == 123) waiter.getLoop().quit(); }); waiter.wait();
In simple cases you could directly write:
waitForTimeout_t(this, &MyClass::triggered, [&](int i) {...}, msTimeout).wait();
It would be little annoying to always have to write
wait()
, though.One other disadvantage would be that I would assume that the last few lines (
if(time.isActive())...
) would be per specific use cases. With my first suggestion the template functionwaitForTimeout(...)
could just return abool
which tells you if the timer did fire.The thing is that this approach should not be your goto solution. Nested loops are considered evil in Qt. Nothing is preventing you from becoming deeply nested. Qt documentation itself discourages using nested loops. They should be rarely used. Thus, it is best to not write a template for this because it would encourage using this approach.