diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h index 5b4c929a361..d8fe946b923 100644 --- a/src/corelib/thread/qfuture_impl.h +++ b/src/corelib/thread/qfuture_impl.h @@ -590,6 +590,18 @@ void Continuation::create(F &&func, f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d); } +// defined in qfutureinterface.cpp: +Q_CORE_EXPORT void watchContinuationImpl(const QObject *context, QSlotObjectBase *slotObj, + QFutureInterfaceBase &fi); +template +void watchContinuation(const QObject *context, Continuation &&c, QFutureInterfaceBase &fi) +{ + using Prototype = typename QtPrivate::Callable::Function; + watchContinuationImpl(context, + QtPrivate::makeCallableObject(std::forward(c)), + fi); +} + template template void Continuation::create(F &&func, @@ -610,15 +622,7 @@ void Continuation::create(F &&func, continuationJob.execute(); }; - auto *watcher = new QBasicFutureWatcher; - watcher->moveToThread(context->thread()); - QObject::connect(watcher, &QBasicFutureWatcher::finished, - context, std::move(continuation)); - QObject::connect(watcher, &QBasicFutureWatcher::finished, - watcher, &QObject::deleteLater); - QObject::connect(context, &QObject::destroyed, - watcher, &QObject::deleteLater); - watcher->setFuture(f->d); + QtPrivate::watchContinuation(context, std::move(continuation), f->d); } template @@ -710,12 +714,7 @@ void FailureHandler::create(F &&function, QFuturemoveToThread(context->thread()); - QObject::connect(watcher, &QBasicFutureWatcher::finished, context, std::move(failureContinuation)); - QObject::connect(watcher, &QBasicFutureWatcher::finished, watcher, &QObject::deleteLater); - QObject::connect(context, &QObject::destroyed, watcher, &QObject::deleteLater); - watcher->setFuture(future->d); + QtPrivate::watchContinuation(context, std::move(failureContinuation), future->d); } template @@ -809,13 +808,7 @@ public: run(std::forward(handler), parentFuture, std::move(promise)); }; - auto *watcher = new QBasicFutureWatcher; - watcher->moveToThread(context->thread()); - QObject::connect(watcher, &QBasicFutureWatcher::finished, - context, std::move(canceledContinuation)); - QObject::connect(watcher, &QBasicFutureWatcher::finished, watcher, &QObject::deleteLater); - QObject::connect(context, &QObject::destroyed, watcher, &QObject::deleteLater); - watcher->setFuture(future->d); + QtPrivate::watchContinuation(context, std::move(canceledContinuation), future->d); } template diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp index 8f73dde2537..de936005c34 100644 --- a/src/corelib/thread/qfutureinterface.cpp +++ b/src/corelib/thread/qfutureinterface.cpp @@ -4,12 +4,14 @@ // qfutureinterface.h included from qfuture.h #include "qfuture.h" #include "qfutureinterface_p.h" +#include "qbasicfuturewatcher.h" #include #include #include #include // for qYieldCpu() #include +#include #ifdef interface # undef interface @@ -43,6 +45,36 @@ const auto suspendingOrSuspended = } // unnamed namespace +void QtPrivate::watchContinuationImpl(const QObject *context, QSlotObjectBase *slotObj, + QFutureInterfaceBase &fi) +{ + Q_ASSERT(context); + Q_ASSERT(slotObj); + + // ### we're missing `QSlotObjectPtr`... + struct Deleter { + void operator()(QSlotObjectBase *p) const { p->destroyIfLastRef(); } + }; + auto slot = std::unique_ptr(slotObj); + + auto *watcher = new QBasicFutureWatcher; + watcher->moveToThread(context->thread()); + // ### we're missing a convenient way to `QObject::connect()` to a `QSlotObjectBase`... + QObject::connect(watcher, &QBasicFutureWatcher::finished, + // for the following, cf. QMetaObject::invokeMethodImpl(): + // we know `slot` is a lambda returning `void`, so we can just + // `call()` with `obj` and `args[0]` set to `nullptr`: + watcher, [slot = std::move(slot)] { + void *args[] = { nullptr }; // for `void` return value + slot->call(nullptr, args); + }); + QObject::connect(watcher, &QBasicFutureWatcher::finished, + watcher, &QObject::deleteLater); + QObject::connect(context, &QObject::destroyed, + watcher, &QObject::deleteLater); + watcher->setFuture(fi); +} + QFutureCallOutInterface::~QFutureCallOutInterface() = default;