QtFuture::connect: exclude QPrivateSignal from the resulting future type

Filter out the last argument of type QPrivateSignal from the signal's
arguments passed to QtFuture::connect().

Pick-to: 6.2
Fixes: QTBUG-92501
Change-Id: Idcd6baba1f01fcc94fa64b1c7030a629d01ed7a1
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
bb10
Sona Kurazyan 2021-12-09 21:49:40 +01:00 committed by Marc Mutz
parent 799660d679
commit ed546ff216
2 changed files with 91 additions and 8 deletions

View File

@ -129,7 +129,48 @@ struct ResultTypeHelper<
using ResultType = std::invoke_result_t<std::decay_t<F>>;
};
// Helpers to remove QPrivateSignal argument from the list of arguments
template<class T, class Enable = void>
inline constexpr bool IsPrivateSignalArg = false;
template<class T>
inline constexpr bool IsPrivateSignalArg<T, typename std::enable_if_t<
// finds injected-class-name, the 'class' avoids falling into the rules of [class.qual]/2:
std::is_class_v<class T::QPrivateSignal>
>> = true;
template<class Tuple, std::size_t... I>
auto cutTuple(Tuple &&t, std::index_sequence<I...>)
{
return std::make_tuple(std::get<I>(t)...);
}
template<class Arg, class... Args>
auto createTuple(Arg &&arg, Args &&... args)
{
using TupleType = std::tuple<std::decay_t<Arg>, std::decay_t<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;
} else {
return cutTuple(std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...),
std::make_index_sequence<Size>());
}
} else {
return std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...);
}
}
// Helpers to resolve argument types of callables.
template<class Arg, class... Args>
using FilterLastPrivateSignalArg =
std::conditional_t<(sizeof...(Args) > 0),
std::invoke_result_t<decltype(createTuple<Arg, Args...>), Arg, Args...>,
std::conditional_t<IsPrivateSignalArg<Arg>, void, Arg>>;
template<typename...>
struct ArgsType;
@ -140,9 +181,7 @@ struct ArgsType<Arg, Args...>
using PromiseType = void;
using IsPromise = std::false_type;
static const bool HasExtraArgs = (sizeof...(Args) > 0);
using AllArgs =
std::conditional_t<HasExtraArgs, std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>,
std::decay_t<Arg>>;
using AllArgs = FilterLastPrivateSignalArg<std::decay_t<Arg>, std::decay_t<Args>...>;
template<class Class, class Callable>
static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, Arg, Args...>;
@ -155,9 +194,7 @@ struct ArgsType<QPromise<Arg> &, Args...>
using PromiseType = Arg;
using IsPromise = std::true_type;
static const bool HasExtraArgs = (sizeof...(Args) > 0);
using AllArgs =
std::conditional_t<HasExtraArgs, std::tuple<std::decay_t<QPromise<Arg> &>, std::decay_t<Args>...>,
std::decay_t<QPromise<Arg> &>>;
using AllArgs = FilterLastPrivateSignalArg<QPromise<Arg>, std::decay_t<Args>...>;
template<class Class, class Callable>
static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, QPromise<Arg> &, Args...>;
@ -899,7 +936,8 @@ static QFuture<ArgsType<Signal>> 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 {

View File

@ -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<int, double, QString> 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();