diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h index 136892ddaf..869a791b15 100644 --- a/src/corelib/thread/qfuture_impl.h +++ b/src/corelib/thread/qfuture_impl.h @@ -129,7 +129,48 @@ struct ResultTypeHelper< using ResultType = std::invoke_result_t>; }; +// Helpers to remove QPrivateSignal argument from the list of arguments + +template +inline constexpr bool IsPrivateSignalArg = false; + +template +inline constexpr bool IsPrivateSignalArg + >> = true; + +template +auto cutTuple(Tuple &&t, std::index_sequence) +{ + return std::make_tuple(std::get(t)...); +} + +template +auto createTuple(Arg &&arg, Args &&... args) +{ + using TupleType = std::tuple, std::decay_t...>; + constexpr auto Size = sizeof...(Args); // One less than the size of all arguments + if constexpr (QtPrivate::IsPrivateSignalArg>) { + if constexpr (Size == 1) { + return arg; + } else { + return cutTuple(std::make_tuple(std::forward(arg), std::forward(args)...), + std::make_index_sequence()); + } + } else { + return std::make_tuple(std::forward(arg), std::forward(args)...); + } +} + // Helpers to resolve argument types of callables. + +template +using FilterLastPrivateSignalArg = + std::conditional_t<(sizeof...(Args) > 0), + std::invoke_result_t), Arg, Args...>, + std::conditional_t, void, Arg>>; + template struct ArgsType; @@ -140,9 +181,7 @@ struct ArgsType using PromiseType = void; using IsPromise = std::false_type; static const bool HasExtraArgs = (sizeof...(Args) > 0); - using AllArgs = - std::conditional_t, std::decay_t...>, - std::decay_t>; + using AllArgs = FilterLastPrivateSignalArg, std::decay_t...>; template static const bool CanInvokeWithArgs = std::is_invocable_v; @@ -155,9 +194,7 @@ struct ArgsType &, Args...> using PromiseType = Arg; using IsPromise = std::true_type; static const bool HasExtraArgs = (sizeof...(Args) > 0); - using AllArgs = - std::conditional_t &>, std::decay_t...>, - std::decay_t &>>; + using AllArgs = FilterLastPrivateSignalArg, std::decay_t...>; template static const bool CanInvokeWithArgs = std::is_invocable_v &, Args...>; @@ -899,7 +936,8 @@ static QFuture> connect(Sender *sender, Signal signal) [promise, connections](auto... values) mutable { QObject::disconnect(connections->first); QObject::disconnect(connections->second); - promise.reportResult(std::make_tuple(values...)); + promise.reportResult(QtPrivate::createTuple( + std::move(values)...)); promise.reportFinished(); }); } else { diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index f97caa0633..7b272cf5a3 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -70,11 +70,23 @@ public: emit multipleArgs(value1, value2, value3); } + void emitNoArgPrivateSignal() { emit noArgPrivateSignal(QPrivateSignal()); } + void emitIntArgPrivateSignal(int value) { emit intArgPrivateSignal(value, QPrivateSignal()); } + void emitMultiArgsPrivateSignal(int value1, double value2, const QString &value3) + { + emit multiArgsPrivateSignal(value1, value2, value3, QPrivateSignal()); + } + signals: void noArgSignal(); void intArgSignal(int value); void constRefArg(const QString &value); void multipleArgs(int value1, double value2, const QString &value3); + + // Private signals + void noArgPrivateSignal(QPrivateSignal); + void intArgPrivateSignal(int value, QPrivateSignal); + void multiArgsPrivateSignal(int value1, double value2, const QString &value3, QPrivateSignal); }; class LambdaThread : public QThread @@ -3433,7 +3445,7 @@ void tst_QFuture::signalConnect() { SenderObject sender; auto future = - QtFuture::connect(&sender, &SenderObject::noArgSignal).then([&] { return true; }); + QtFuture::connect(&sender, &SenderObject::noArgSignal).then([] { return true; }); sender.emitNoArg(); QCOMPARE(future.result(), true); } @@ -3474,6 +3486,39 @@ void tst_QFuture::signalConnect() QCOMPARE(std::get<2>(result), "42"); } + // No arg private signal + { + SenderObject sender; + auto future = QtFuture::connect(&sender, &SenderObject::noArgPrivateSignal).then([] { + return true; + }); + sender.emitNoArgPrivateSignal(); + QCOMPARE(future.result(), true); + } + + // One arg private signal + { + SenderObject sender; + auto future = + QtFuture::connect(&sender, &SenderObject::intArgPrivateSignal).then([](int value) { + return value; + }); + sender.emitIntArgPrivateSignal(42); + QCOMPARE(future.result(), 42); + } + + // Multi-args private signal + { + SenderObject sender; + auto future = QtFuture::connect(&sender, &SenderObject::multiArgsPrivateSignal) + .then([](std::tuple values) { return values; }); + sender.emitMultiArgsPrivateSignal(42, 42.5, "42"); + const auto [i, d, s] = future.result(); + QCOMPARE(i, 42); + QCOMPARE(d, 42.5); + QCOMPARE(s, "42"); + } + // Sender destroyed { SenderObject *sender = new SenderObject();