summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/thread/qfuture_impl.h51
-rw-r--r--tests/auto/corelib/thread/qfuture/CMakeLists.txt5
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp66
3 files changed, 114 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();
}
diff --git a/tests/auto/corelib/thread/qfuture/CMakeLists.txt b/tests/auto/corelib/thread/qfuture/CMakeLists.txt
index dcf7846fd2..df5826032d 100644
--- a/tests/auto/corelib/thread/qfuture/CMakeLists.txt
+++ b/tests/auto/corelib/thread/qfuture/CMakeLists.txt
@@ -12,3 +12,8 @@ qt_internal_add_test(tst_qfuture
PUBLIC_LIBRARIES
Qt::CorePrivate
)
+
+qt_internal_extend_target(tst_qmetatype CONDITION MSVC
+ COMPILE_OPTIONS
+ /bigobj
+)
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index 385fbe7fca..f97caa0633 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -145,6 +145,7 @@ private slots:
void onCanceled();
void cancelContinuations();
void continuationsWithContext();
+ void continuationsWithMoveOnlyLambda();
#if 0
// TODO: enable when QFuture::takeResults() is enabled
void takeResults();
@@ -3111,6 +3112,71 @@ void tst_QFuture::continuationsWithContext()
thread.wait();
}
+void tst_QFuture::continuationsWithMoveOnlyLambda()
+{
+ // .then()
+ {
+ std::unique_ptr<int> uniquePtr(new int(42));
+ auto future = QtFuture::makeReadyFuture().then([p = std::move(uniquePtr)] { return *p; });
+ QCOMPARE(future.result(), 42);
+ }
+ // .then() with thread pool
+ {
+ QThreadPool pool;
+
+ std::unique_ptr<int> uniquePtr(new int(42));
+ auto future =
+ QtFuture::makeReadyFuture().then(&pool, [p = std::move(uniquePtr)] { return *p; });
+ QCOMPARE(future.result(), 42);
+ }
+ // .then() with context
+ {
+ QObject object;
+
+ std::unique_ptr<int> uniquePtr(new int(42));
+ auto future = QtFuture::makeReadyFuture().then(&object,
+ [p = std::move(uniquePtr)] { return *p; });
+ QCOMPARE(future.result(), 42);
+ }
+
+ // .onCanceled()
+ {
+ std::unique_ptr<int> uniquePtr(new int(42));
+ auto future =
+ createCanceledFuture<int>().onCanceled([p = std::move(uniquePtr)] { return *p; });
+ QCOMPARE(future.result(), 42);
+ }
+
+ // .onCanceled() with context
+ {
+ QObject object;
+
+ std::unique_ptr<int> uniquePtr(new int(42));
+ auto future = createCanceledFuture<int>().onCanceled(
+ &object, [p = std::move(uniquePtr)] { return *p; });
+ QCOMPARE(future.result(), 42);
+ }
+
+#ifndef QT_NO_EXCEPTIONS
+ // .onFailed()
+ {
+ std::unique_ptr<int> uniquePtr(new int(42));
+ auto future = QtFuture::makeExceptionalFuture<int>(QException())
+ .onFailed([p = std::move(uniquePtr)] { return *p; });
+ QCOMPARE(future.result(), 42);
+ }
+ // .onFailed() with context
+ {
+ QObject object;
+
+ std::unique_ptr<int> uniquePtr(new int(42));
+ auto future = QtFuture::makeExceptionalFuture<int>(QException())
+ .onFailed(&object, [p = std::move(uniquePtr)] { return *p; });
+ QCOMPARE(future.result(), 42);
+ }
+#endif // QT_NO_EXCEPTIONS
+}
+
void tst_QFuture::testSingleResult(const UniquePtr &p)
{
QVERIFY(p.get() != nullptr);