QtConcurrent::run: support non default-constructible return types
The QtConcurrent::RunFunctionTask class keeps a variable to store the result of QtConcurrent::run when it becomes available, so that it can be reported afterwards. This requires the result type to be default-constructible. However there's no need in storing the result, it can be reported immediately after it becomes available. Pick-to: 6.1 6.2 Fixes: QTBUG-95214 Change-Id: I95f3dbff0ab41eaa81b104a8834b37d10a0d193a Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io> Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
parent
c4ac9e74c7
commit
642b9fce81
@ -117,37 +117,15 @@ public:
|
|||||||
promise.reportException(QUnhandledException(std::current_exception()));
|
promise.reportException(QUnhandledException(std::current_exception()));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
reportResult();
|
|
||||||
|
|
||||||
promise.reportFinished();
|
promise.reportFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void runFunctor() = 0;
|
virtual void runFunctor() = 0;
|
||||||
virtual void reportResult() {}
|
|
||||||
|
|
||||||
QFutureInterface<T> promise;
|
QFutureInterface<T> promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class RunFunctionTask : public RunFunctionTaskBase<T>
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
void reportResult() override
|
|
||||||
{
|
|
||||||
if constexpr (std::is_move_constructible_v<T>)
|
|
||||||
this->promise.reportAndMoveResult(std::move(result));
|
|
||||||
else if constexpr (std::is_copy_constructible_v<T>)
|
|
||||||
this->promise.reportResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
T result;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class RunFunctionTask<void> : public RunFunctionTaskBase<void> {};
|
|
||||||
|
|
||||||
} //namespace QtConcurrent
|
} //namespace QtConcurrent
|
||||||
|
|
||||||
#endif //Q_QDOC
|
#endif //Q_QDOC
|
||||||
|
@ -138,7 +138,7 @@ template <class ...Types>
|
|||||||
using DecayedTuple = std::tuple<std::decay_t<Types>...>;
|
using DecayedTuple = std::tuple<std::decay_t<Types>...>;
|
||||||
|
|
||||||
template <class Function, class ...Args>
|
template <class Function, class ...Args>
|
||||||
struct StoredFunctionCall : public RunFunctionTask<InvokeResultType<Function, Args...>>
|
struct StoredFunctionCall : public RunFunctionTaskBase<InvokeResultType<Function, Args...>>
|
||||||
{
|
{
|
||||||
StoredFunctionCall(DecayedTuple<Function, Args...> &&_data)
|
StoredFunctionCall(DecayedTuple<Function, Args...> &&_data)
|
||||||
: data(std::move(_data))
|
: data(std::move(_data))
|
||||||
@ -152,10 +152,17 @@ protected:
|
|||||||
return std::invoke(function, args...);
|
return std::invoke(function, args...);
|
||||||
};
|
};
|
||||||
|
|
||||||
if constexpr (std::is_void_v<InvokeResultType<Function, Args...>>)
|
if constexpr (std::is_void_v<InvokeResultType<Function, Args...>>) {
|
||||||
std::apply(invoke, std::move(data));
|
std::apply(invoke, std::move(data));
|
||||||
else
|
} else {
|
||||||
this->result = std::apply(invoke, std::move(data));
|
auto result = std::apply(invoke, std::move(data));
|
||||||
|
|
||||||
|
using T = InvokeResultType<Function, Args...>;
|
||||||
|
if constexpr (std::is_move_constructible_v<T>)
|
||||||
|
this->promise.reportAndMoveResult(std::move(result));
|
||||||
|
else if constexpr (std::is_copy_constructible_v<T>)
|
||||||
|
this->promise.reportResult(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -64,6 +64,7 @@ private slots:
|
|||||||
void moveOnlyType();
|
void moveOnlyType();
|
||||||
void crefFunction();
|
void crefFunction();
|
||||||
void customPromise();
|
void customPromise();
|
||||||
|
void nonDefaultConstructibleValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
void light()
|
void light()
|
||||||
@ -1564,6 +1565,17 @@ void tst_QtConcurrentRun::customPromise()
|
|||||||
QCOMPARE(p.future().progressMaximum(), 10);
|
QCOMPARE(p.future().progressMaximum(), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QtConcurrentRun::nonDefaultConstructibleValue()
|
||||||
|
{
|
||||||
|
struct NonDefaultConstructible
|
||||||
|
{
|
||||||
|
explicit NonDefaultConstructible(int v) : value(v) { }
|
||||||
|
int value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto future = QtConcurrent::run([] { return NonDefaultConstructible(42); });
|
||||||
|
QCOMPARE(future.result().value, 42);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QtConcurrentRun)
|
QTEST_MAIN(tst_QtConcurrentRun)
|
||||||
#include "tst_qtconcurrentrun.moc"
|
#include "tst_qtconcurrentrun.moc"
|
||||||
|
@ -229,12 +229,12 @@ void tst_QFutureWatcher::canceled()
|
|||||||
future.waitForFinished();
|
future.waitForFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
class IntTask : public RunFunctionTask<int>
|
class IntTask : public RunFunctionTaskBase<int>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void runFunctor() override
|
void runFunctor() override
|
||||||
{
|
{
|
||||||
result = 10;
|
promise.reportResult(10);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -463,7 +463,7 @@ void tst_QFutureWatcher::disconnectRunningFuture()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int maxProgress = 100000;
|
const int maxProgress = 100000;
|
||||||
class ProgressEmitterTask : public RunFunctionTask<void>
|
class ProgressEmitterTask : public RunFunctionTaskBase<void>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void runFunctor() override
|
void runFunctor() override
|
||||||
@ -493,7 +493,7 @@ void tst_QFutureWatcher::tooMuchProgress()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ProgressTextTask : public RunFunctionTask<T>
|
class ProgressTextTask : public RunFunctionTaskBase<T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void runFunctor() override
|
void runFunctor() override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user