diff options
author | Sona Kurazyan <sona.kurazyan@qt.io> | 2021-11-29 17:36:57 +0100 |
---|---|---|
committer | Sona Kurazyan <sona.kurazyan@qt.io> | 2021-12-01 01:58:18 +0100 |
commit | 3be72253a6c8f469626d931b623f548cfe1e81a7 (patch) | |
tree | 40152cea64e1cf8e3e0e84d9c3ee60c2d6e98f17 /src | |
parent | 1a61b85a2c04d48496a2e83359bf1d65abbc14dc (diff) |
Fix QFuture continuations/handlers to work with move-only callables
std::function, which is used to store the type-erased continuation
lambdas, requires the passed callable to be copy-constructible. This
makes impossible to use move-only callables with continuations/handlers.
In particular, it makes impossible passing lambdas that are capturing
move-only objects. The workaround is to store the continuation lambda
inside a wrapper for the callable, which stores the move-only lambda in
a QSharedPtr and can be stored in std::function, since it's copyable.
Pick-to: 6.2
Fixes: QTBUG-98493
Change-Id: I8b7a22fcf68dc132b3c533216a7a1665e9f9fb0a
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/thread/qfuture_impl.h | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h index e5a15b57ff..136892ddaf 100644 --- a/src/corelib/thread/qfuture_impl.h +++ b/src/corelib/thread/qfuture_impl.h @@ -498,6 +498,17 @@ bool Continuation<Function, ResultType, ParentResultType>::execute() return true; } +// Workaround for keeping move-only lambdas inside std::function +template<class Function> +struct ContinuationWrapper +{ + ContinuationWrapper(Function &&f) : function(QSharedPointer<Function>::create(std::move(f))) { } + void operator()(const QFutureInterfaceBase &parentData) { (*function)(parentData); } + +private: + QSharedPointer<Function> function; +}; + template<typename Function, typename ResultType, typename ParentResultType> template<typename F> void Continuation<Function, ResultType, ParentResultType>::create(F &&func, @@ -543,8 +554,10 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func, continuationJob = nullptr; } }; - - f->d.setContinuation(std::move(continuation), p.d); + if constexpr (!std::is_copy_constructible_v<Function>) + f->d.setContinuation(ContinuationWrapper(std::move(continuation)), p.d); + else + f->d.setContinuation(std::move(continuation), p.d); } template<typename Function, typename ResultType, typename ParentResultType> @@ -573,7 +586,10 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func, } }; - f->d.setContinuation(std::move(continuation), p.d); + if constexpr (!std::is_copy_constructible_v<Function>) + f->d.setContinuation(ContinuationWrapper(std::move(continuation)), p.d); + else + f->d.setContinuation(std::move(continuation), p.d); } template<typename Function, typename ResultType, typename ParentResultType> @@ -596,7 +612,10 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func, }); }; - f->d.setContinuation(std::move(continuation), p.d); + if constexpr (!std::is_copy_constructible_v<Function>) + f->d.setContinuation(ContinuationWrapper(std::move(continuation)), p.d); + else + f->d.setContinuation(std::move(continuation), p.d); } template<typename Function, typename ResultType, typename ParentResultType> @@ -675,7 +694,10 @@ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultTy failureHandler.run(); }; - future->d.setContinuation(std::move(failureContinuation)); + if constexpr (!std::is_copy_constructible_v<Function>) + future->d.setContinuation(ContinuationWrapper(std::move(failureContinuation))); + else + future->d.setContinuation(std::move(failureContinuation)); } template<class Function, class ResultType> @@ -699,7 +721,10 @@ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultTy }); }; - future->d.setContinuation(std::move(failureContinuation)); + if constexpr (!std::is_copy_constructible_v<Function>) + future->d.setContinuation(ContinuationWrapper(std::move(failureContinuation))); + else + future->d.setContinuation(std::move(failureContinuation)); } template<class Function, class ResultType> @@ -782,7 +807,12 @@ public: auto parentFuture = QFutureInterface<ResultType>(parentData).future(); run(std::forward<F>(handler), parentFuture, promise); }; - future->d.setContinuation(std::move(canceledContinuation)); + + if constexpr (!std::is_copy_constructible_v<Function>) + future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation))); + else + future->d.setContinuation(std::move(canceledContinuation)); + return promise.future(); } @@ -802,7 +832,12 @@ public: run(std::forward<F>(handler), parentFuture, promise); }); }; - future->d.setContinuation(std::move(canceledContinuation)); + + if constexpr (!std::is_copy_constructible_v<Function>) + future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation))); + else + future->d.setContinuation(std::move(canceledContinuation)); + return promise.future(); } |