summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread/qfuture_impl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/thread/qfuture_impl.h')
-rw-r--r--src/corelib/thread/qfuture_impl.h336
1 files changed, 198 insertions, 138 deletions
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 2924408333..351093adc7 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFUTURE_H
#error Do not include qfuture_impl.h directly
@@ -50,9 +14,10 @@
#include <QtCore/qfutureinterface.h>
#include <QtCore/qthreadpool.h>
#include <QtCore/qexception.h>
-#include <QtCore/qpointer.h>
#include <QtCore/qpromise.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
//
@@ -150,7 +115,7 @@ auto createTuple(Arg &&arg, Args &&... args)
constexpr auto Size = sizeof...(Args); // One less than the size of all arguments
if constexpr (QtPrivate::IsPrivateSignalArg<std::tuple_element_t<Size, TupleType>>) {
if constexpr (Size == 1) {
- return arg;
+ return std::forward<Arg>(arg);
} else {
return cutTuple(std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...),
std::make_index_sequence<Size>());
@@ -279,17 +244,6 @@ template<class Class, class Callable>
using EnableIfInvocable = std::enable_if_t<
QtPrivate::ArgResolver<Callable>::template CanInvokeWithArgs<Class, Callable>>;
-template<class>
-struct isTuple : std::false_type
-{
-};
-template<class... T>
-struct isTuple<std::tuple<T...>> : std::true_type
-{
-};
-template<class T>
-inline constexpr bool isTupleV = isTuple<T>::value;
-
template<class T>
inline constexpr bool isQFutureV = false;
@@ -319,6 +273,12 @@ using IsRandomAccessible =
std::begin(std::declval<Sequence>()))>>::iterator_category,
std::random_access_iterator_tag>;
+template<class Sequence>
+using HasInputIterator =
+ std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
+ std::begin(std::declval<Sequence>()))>>::iterator_category,
+ std::input_iterator_tag>;
+
template<class Iterator>
using IsForwardIterable =
std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category,
@@ -327,6 +287,7 @@ using IsForwardIterable =
template<typename Function, typename ResultType, typename ParentResultType>
class Continuation
{
+ Q_DISABLE_COPY_MOVE(Continuation)
public:
template<typename F = Function>
Continuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p)
@@ -470,7 +431,7 @@ void Continuation<Function, ResultType, ParentResultType>::runFunction()
fulfillPromiseWithResult();
} else {
// This assert normally should never fail, this is to make sure
- // that nothing unexpected happend.
+ // that nothing unexpected happened.
static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
"The continuation is not invocable with the provided arguments");
fulfillPromise(parentFuture);
@@ -485,7 +446,7 @@ void Continuation<Function, ResultType, ParentResultType>::runFunction()
fulfillVoidPromise();
} else {
// This assert normally should never fail, this is to make sure
- // that nothing unexpected happend.
+ // that nothing unexpected happened.
static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
"The continuation is not invocable with the provided arguments");
function(parentFuture);
@@ -574,18 +535,18 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
fi.setLaunchAsync(launchAsync);
- auto continuation = [func = std::forward<F>(func), fi, promise = QPromise(fi), pool,
+ auto continuation = [func = std::forward<F>(func), fi, promise_ = QPromise(fi), pool,
launchAsync](const QFutureInterfaceBase &parentData) mutable {
const auto parent = QFutureInterface<ParentResultType>(parentData).future();
Continuation<Function, ResultType, ParentResultType> *continuationJob = nullptr;
if (launchAsync) {
auto asyncJob = new AsyncContinuation<Function, ResultType, ParentResultType>(
- std::forward<Function>(func), parent, std::move(promise), pool);
+ std::forward<Function>(func), parent, std::move(promise_), pool);
fi.setRunnable(asyncJob);
continuationJob = asyncJob;
} else {
continuationJob = new SyncContinuation<Function, ResultType, ParentResultType>(
- std::forward<Function>(func), parent, std::move(promise));
+ std::forward<Function>(func), parent, std::move(promise_));
}
bool isLaunched = continuationJob->execute();
@@ -612,11 +573,11 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
fi.setLaunchAsync(true);
fi.setThreadPool(pool);
- auto continuation = [func = std::forward<F>(func), promise = QPromise(fi),
+ auto continuation = [func = std::forward<F>(func), promise_ = QPromise(fi),
pool](const QFutureInterfaceBase &parentData) mutable {
const auto parent = QFutureInterface<ParentResultType>(parentData).future();
auto continuationJob = new AsyncContinuation<Function, ResultType, ParentResultType>(
- std::forward<Function>(func), parent, std::move(promise), pool);
+ std::forward<Function>(func), parent, std::move(promise_), pool);
bool isLaunched = continuationJob->execute();
// If continuation is successfully launched, AsyncContinuation will be deleted
// by the QThreadPool which has started it.
@@ -628,6 +589,15 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d);
}
+template <typename Continuation>
+void watchContinuation(const QObject *context, Continuation &&c, QFutureInterfaceBase &fi)
+{
+ using Prototype = typename QtPrivate::Callable<Continuation>::Function;
+ watchContinuationImpl(context,
+ QtPrivate::makeCallableObject<Prototype>(std::forward<Continuation>(c)),
+ fi);
+}
+
template<typename Function, typename ResultType, typename ParentResultType>
template<typename F>
void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
@@ -636,21 +606,19 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
QObject *context)
{
Q_ASSERT(f);
-
- auto continuation = [func = std::forward<F>(func), promise = QPromise(fi),
- context = QPointer<QObject>(context)](
- const QFutureInterfaceBase &parentData) mutable {
- Q_ASSERT(context);
- const auto parent = QFutureInterface<ParentResultType>(parentData).future();
- QMetaObject::invokeMethod(
- context,
- [func = std::forward<F>(func), promise = std::move(promise), parent]() mutable {
- SyncContinuation<Function, ResultType, ParentResultType> continuationJob(
- std::forward<Function>(func), parent, std::move(promise));
- continuationJob.execute();
- });
+ Q_ASSERT(context);
+
+ // When the context object is destroyed, the signal-slot connection is broken and the
+ // continuation callback is destroyed. The promise that is created in the capture list is
+ // destroyed and, if it is not yet finished, cancelled.
+ auto continuation = [func = std::forward<F>(func), parent = *f,
+ promise_ = QPromise(fi)]() mutable {
+ SyncContinuation<Function, ResultType, ParentResultType> continuationJob(
+ std::forward<Function>(func), parent, std::move(promise_));
+ continuationJob.execute();
};
- f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d);
+
+ QtPrivate::watchContinuation(context, std::move(continuation), f->d);
}
template<typename Function, typename ResultType, typename ParentResultType>
@@ -716,11 +684,11 @@ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultTy
{
Q_ASSERT(future);
- auto failureContinuation = [function = std::forward<F>(function), promise = QPromise(fi)](
+ auto failureContinuation = [function = std::forward<F>(function), promise_ = QPromise(fi)](
const QFutureInterfaceBase &parentData) mutable {
const auto parent = QFutureInterface<ResultType>(parentData).future();
FailureHandler<Function, ResultType> failureHandler(std::forward<Function>(function),
- parent, std::move(promise));
+ parent, std::move(promise_));
failureHandler.run();
};
@@ -734,22 +702,15 @@ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultTy
QObject *context)
{
Q_ASSERT(future);
+ Q_ASSERT(context);
+ auto failureContinuation = [function = std::forward<F>(function),
+ parent = *future, promise_ = QPromise(fi)]() mutable {
+ FailureHandler<Function, ResultType> failureHandler(
+ std::forward<Function>(function), parent, std::move(promise_));
+ failureHandler.run();
+ };
- auto failureContinuation =
- [function = std::forward<F>(function), promise = QPromise(fi),
- context = QPointer<QObject>(context)](const QFutureInterfaceBase &parentData) mutable {
- Q_ASSERT(context);
- const auto parent = QFutureInterface<ResultType>(parentData).future();
- QMetaObject::invokeMethod(context,
- [function = std::forward<F>(function),
- promise = std::move(promise), parent]() mutable {
- FailureHandler<Function, ResultType> failureHandler(
- std::forward<Function>(function), parent, std::move(promise));
- failureHandler.run();
- });
- };
-
- future->d.setContinuation(ContinuationWrapper(std::move(failureContinuation)));
+ QtPrivate::watchContinuation(context, std::move(failureContinuation), future->d);
}
template<class Function, class ResultType>
@@ -766,6 +727,8 @@ void FailureHandler<Function, ResultType>::run()
} else {
handleException<ArgType>();
}
+ } else if (parentFuture.d.isChainCanceled()) {
+ promise.future().cancel();
} else {
QtPrivate::fulfillPromise(promise, parentFuture);
}
@@ -835,19 +798,13 @@ public:
QObject *context)
{
Q_ASSERT(future);
- auto canceledContinuation = [promise = QPromise(fi), handler = std::forward<F>(handler),
- context = QPointer<QObject>(context)](
- const QFutureInterfaceBase &parentData) mutable {
- Q_ASSERT(context);
- auto parentFuture = QFutureInterface<ResultType>(parentData).future();
- QMetaObject::invokeMethod(context,
- [promise = std::move(promise), parentFuture,
- handler = std::forward<F>(handler)]() mutable {
- run(std::forward<F>(handler), parentFuture, std::move(promise));
- });
+ Q_ASSERT(context);
+ auto canceledContinuation = [handler = std::forward<F>(handler),
+ parentFuture = *future, promise = QPromise(fi)]() mutable {
+ run(std::forward<F>(handler), parentFuture, std::move(promise));
};
- future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation)));
+ QtPrivate::watchContinuation(context, std::move(canceledContinuation), future->d);
}
template<class F = Function>
@@ -878,6 +835,69 @@ public:
}
};
+struct UnwrapHandler
+{
+ template<class T>
+ static auto unwrapImpl(T *outer)
+ {
+ Q_ASSERT(outer);
+
+ using ResultType = typename QtPrivate::Future<std::decay_t<T>>::type;
+ using NestedType = typename QtPrivate::Future<ResultType>::type;
+ QFutureInterface<NestedType> promise(QFutureInterfaceBase::State::Pending);
+
+ outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
+ // We use the .then([](QFuture<ResultType> outerFuture) {...}) version
+ // (where outerFuture == *outer), to propagate the exception if the
+ // outer future has failed.
+ Q_ASSERT(outerFuture.isFinished());
+#ifndef QT_NO_EXCEPTIONS
+ if (outerFuture.d.hasException()) {
+ promise.reportStarted();
+ promise.reportException(outerFuture.d.exceptionStore().exception());
+ promise.reportFinished();
+ return;
+ }
+#endif
+
+ promise.reportStarted();
+ ResultType nestedFuture = outerFuture.result();
+
+ nestedFuture.then([promise] (const QFuture<NestedType> &nested) mutable {
+#ifndef QT_NO_EXCEPTIONS
+ if (nested.d.hasException()) {
+ promise.reportException(nested.d.exceptionStore().exception());
+ } else
+#endif
+ {
+ if constexpr (!std::is_void_v<NestedType>)
+ promise.reportResults(nested.results());
+ }
+ promise.reportFinished();
+ }).onCanceled([promise] () mutable {
+ promise.reportCanceled();
+ promise.reportFinished();
+ });
+ }).onCanceled([promise]() mutable {
+ // propagate the cancellation of the outer future
+ promise.reportStarted();
+ promise.reportCanceled();
+ promise.reportFinished();
+ });
+ return promise.future();
+ }
+};
+
+template<typename ValueType>
+QFuture<ValueType> makeReadyRangeFutureImpl(const QList<ValueType> &values)
+{
+ QFutureInterface<ValueType> promise;
+ promise.reportStarted();
+ promise.reportResults(values);
+ promise.reportFinished();
+ return promise.future();
+}
+
} // namespace QtPrivate
namespace QtFuture {
@@ -891,6 +911,11 @@ static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
using ArgsType = ArgsType<Signal>;
QFutureInterface<ArgsType> promise;
promise.reportStarted();
+ if (!sender) {
+ promise.reportCanceled();
+ promise.reportFinished();
+ return promise.future();
+ }
using Connections = std::pair<QMetaObject::Connection, QMetaObject::Connection>;
auto connections = std::make_shared<Connections>();
@@ -902,7 +927,7 @@ static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
QObject::disconnect(connections->second);
promise.reportFinished();
});
- } else if constexpr (QtPrivate::isTupleV<ArgsType>) {
+ } else if constexpr (QtPrivate::ArgResolver<Signal>::HasExtraArgs) {
connections->first = QObject::connect(sender, signal, sender,
[promise, connections](auto... values) mutable {
QObject::disconnect(connections->first);
@@ -921,6 +946,12 @@ static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
});
}
+ if (!connections->first) {
+ promise.reportCanceled();
+ promise.reportFinished();
+ return promise.future();
+ }
+
connections->second =
QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable {
QObject::disconnect(connections->first);
@@ -932,8 +963,37 @@ static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
return promise.future();
}
-template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
-static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
+template<typename Container>
+using if_container_with_input_iterators =
+ std::enable_if_t<QtPrivate::HasInputIterator<Container>::value, bool>;
+
+template<typename Container>
+using ContainedType =
+ typename std::iterator_traits<decltype(
+ std::cbegin(std::declval<Container&>()))>::value_type;
+
+template<typename Container, if_container_with_input_iterators<Container> = true>
+static QFuture<ContainedType<Container>> makeReadyRangeFuture(Container &&container)
+{
+ // handle QList<T> separately, because reportResults() takes a QList
+ // as an input
+ using ValueType = ContainedType<Container>;
+ if constexpr (std::is_convertible_v<q20::remove_cvref_t<Container>, QList<ValueType>>) {
+ return QtPrivate::makeReadyRangeFutureImpl(container);
+ } else {
+ return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{std::cbegin(container),
+ std::cend(container)});
+ }
+}
+
+template<typename ValueType>
+static QFuture<ValueType> makeReadyRangeFuture(std::initializer_list<ValueType> values)
+{
+ return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{values});
+}
+
+template<typename T>
+static QFuture<std::decay_t<T>> makeReadyValueFuture(T &&value)
{
QFutureInterface<std::decay_t<T>> promise;
promise.reportStarted();
@@ -943,30 +1003,26 @@ static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
return promise.future();
}
-#if defined(Q_CLANG_QDOC)
-static QFuture<void> makeReadyFuture()
-#else
-template<typename T = void>
-static QFuture<T> makeReadyFuture()
-#endif
-{
- QFutureInterface<T> promise;
- promise.reportStarted();
- promise.reportFinished();
+Q_CORE_EXPORT QFuture<void> makeReadyVoidFuture(); // implemented in qfutureinterface.cpp
- return promise.future();
+#if QT_DEPRECATED_SINCE(6, 10)
+template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
+QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyValueFuture() instead.")
+static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
+{
+ return makeReadyValueFuture(std::forward<T>(value));
}
+// the void specialization is moved to the end of qfuture.h, because it now
+// uses makeReadyVoidFuture() and required QFuture<void> to be defined.
+
template<typename T>
+QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyRangeFuture() instead.")
static QFuture<T> makeReadyFuture(const QList<T> &values)
{
- QFutureInterface<T> promise;
- promise.reportStarted();
- promise.reportResults(values);
- promise.reportFinished();
-
- return promise.future();
+ return makeReadyRangeFuture(values);
}
+#endif // QT_DEPRECATED_SINCE(6, 10)
#ifndef QT_NO_EXCEPTIONS
@@ -1003,20 +1059,21 @@ struct WhenAllContext
{
using ValueType = typename ResultFutures::value_type;
- WhenAllContext(qsizetype size) : count(size) {}
+ explicit WhenAllContext(qsizetype size) : remaining(size) {}
template<typename T = ValueType>
void checkForCompletion(qsizetype index, T &&future)
{
futures[index] = std::forward<T>(future);
- Q_ASSERT(count > 0);
- if (--count <= 0) {
+ const auto oldRemaining = remaining.fetchAndSubRelaxed(1);
+ Q_ASSERT(oldRemaining > 0);
+ if (oldRemaining <= 1) { // that was the last one
promise.addResult(futures);
promise.finish();
}
}
- QAtomicInteger<qsizetype> count;
+ QAtomicInteger<qsizetype> remaining;
QPromise<ResultFutures> promise;
ResultFutures futures;
};
@@ -1040,14 +1097,15 @@ struct WhenAnyContext
};
template<qsizetype Index, typename ContextType, typename... Ts>
-void addCompletionHandlersImpl(const QSharedPointer<ContextType> &context,
+void addCompletionHandlersImpl(const std::shared_ptr<ContextType> &context,
const std::tuple<Ts...> &t)
{
auto future = std::get<Index>(t);
using ResultType = typename ContextType::ValueType;
- future.then([context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
+ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
+ future.then([context=context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, f });
- }).onCanceled([context, future]() {
+ }).onCanceled([context=context, future]() {
context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, future });
});
@@ -1056,7 +1114,7 @@ void addCompletionHandlersImpl(const QSharedPointer<ContextType> &context,
}
template<typename ContextType, typename... Ts>
-void addCompletionHandlers(const QSharedPointer<ContextType> &context, const std::tuple<Ts...> &t)
+void addCompletionHandlers(const std::shared_ptr<ContextType> &context, const std::tuple<Ts...> &t)
{
constexpr qsizetype size = std::tuple_size<std::tuple<Ts...>>::value;
addCompletionHandlersImpl<size - 1, ContextType, Ts...>(context, t);
@@ -1067,17 +1125,18 @@ QFuture<OutputSequence> whenAllImpl(InputIt first, InputIt last)
{
const qsizetype size = std::distance(first, last);
if (size == 0)
- return QtFuture::makeReadyFuture(OutputSequence());
+ return QtFuture::makeReadyValueFuture(OutputSequence());
- auto context = QSharedPointer<QtPrivate::WhenAllContext<OutputSequence>>::create(size);
+ const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
context->futures.resize(size);
context->promise.start();
qsizetype idx = 0;
for (auto it = first; it != last; ++it, ++idx) {
- it->then([context, idx](const ValueType &f) {
+ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
+ it->then([context=context, idx](const ValueType &f) {
context->checkForCompletion(idx, f);
- }).onCanceled([context, idx, f = *it] {
+ }).onCanceled([context=context, idx, f = *it] {
context->checkForCompletion(idx, f);
});
}
@@ -1088,7 +1147,7 @@ template<typename OutputSequence, typename... Futures>
QFuture<OutputSequence> whenAllImpl(Futures &&... futures)
{
constexpr qsizetype size = sizeof...(Futures);
- auto context = QSharedPointer<QtPrivate::WhenAllContext<OutputSequence>>::create(size);
+ const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
context->futures.resize(size);
context->promise.start();
@@ -1106,18 +1165,19 @@ QFuture<QtFuture::WhenAnyResult<typename Future<ValueType>::type>> whenAnyImpl(I
const qsizetype size = std::distance(first, last);
if (size == 0) {
- return QtFuture::makeReadyFuture(
+ return QtFuture::makeReadyValueFuture(
QtFuture::WhenAnyResult { qsizetype(-1), QFuture<PackagedType>() });
}
- auto context = QSharedPointer<QtPrivate::WhenAnyContext<ResultType>>::create();
+ const auto context = std::make_shared<QtPrivate::WhenAnyContext<ResultType>>();
context->promise.start();
qsizetype idx = 0;
for (auto it = first; it != last; ++it, ++idx) {
- it->then([context, idx](const ValueType &f) {
+ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
+ it->then([context=context, idx](const ValueType &f) {
context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
- }).onCanceled([context, idx, f = *it] {
+ }).onCanceled([context=context, idx, f = *it] {
context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
});
}
@@ -1129,7 +1189,7 @@ QFuture<std::variant<std::decay_t<Futures>...>> whenAnyImpl(Futures &&... future
{
using ResultType = std::variant<std::decay_t<Futures>...>;
- auto context = QSharedPointer<QtPrivate::WhenAnyContext<ResultType>>::create();
+ const auto context = std::make_shared<QtPrivate::WhenAnyContext<ResultType>>();
context->promise.start();
QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));