QtFuture::connect: fix for signals with a single std::tuple argument
If the signal passed to QtFuture::connect() takes multiple arguments, we need to wrap the arguments in a std::tuple when reporting the result. To detect this case we were checking if the result type of a QFuture returned by QtFuture::connect() is a std::tuple, but this was not correct: the result type could be a std::tuple also if the passed signal takes a single std::tuple argument. Instead, check if the signal takes more than one argument. As a drive-by modified the tst_QFuture::signalConnect to use const values for tuples used in multiple test-cases, to avoid repetition. Fixes: QTBUG-100071 Pick-to: 6.2 6.3 Change-Id: I1ce39cf87028f36ef94a9d1a4423b0c51473afd4 Reviewed-by: Marc Mutz <marc.mutz@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
26fa539ad2
commit
f2f5c7d2b7
@ -279,17 +279,6 @@ template<class Class, class Callable>
|
|||||||
using EnableIfInvocable = std::enable_if_t<
|
using EnableIfInvocable = std::enable_if_t<
|
||||||
QtPrivate::ArgResolver<Callable>::template CanInvokeWithArgs<Class, Callable>>;
|
QtPrivate::ArgResolver<Callable>::template CanInvokeWithArgs<Class, Callable>>;
|
||||||
|
|
||||||
template<class>
|
|
||||||
struct isTuple : std::false_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
template<class... T>
|
|
||||||
struct isTuple<std::tuple<T...>> : std::true_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
template<class T>
|
|
||||||
inline constexpr bool isTupleV = isTuple<T>::value;
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline constexpr bool isQFutureV = false;
|
inline constexpr bool isQFutureV = false;
|
||||||
|
|
||||||
@ -902,7 +891,7 @@ static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
|
|||||||
QObject::disconnect(connections->second);
|
QObject::disconnect(connections->second);
|
||||||
promise.reportFinished();
|
promise.reportFinished();
|
||||||
});
|
});
|
||||||
} else if constexpr (QtPrivate::isTupleV<ArgsType>) {
|
} else if constexpr (QtPrivate::ArgResolver<Signal>::HasExtraArgs) {
|
||||||
connections->first = QObject::connect(sender, signal, sender,
|
connections->first = QObject::connect(sender, signal, sender,
|
||||||
[promise, connections](auto... values) mutable {
|
[promise, connections](auto... values) mutable {
|
||||||
QObject::disconnect(connections->first);
|
QObject::disconnect(connections->first);
|
||||||
|
@ -64,6 +64,23 @@ public:
|
|||||||
{
|
{
|
||||||
emit multipleArgs(value1, value2, value3);
|
emit multipleArgs(value1, value2, value3);
|
||||||
}
|
}
|
||||||
|
void emitTupleArgSignal(const std::tuple<int, double, QString> &t) { emit tupleArgSignal(t); }
|
||||||
|
void emitMultiArgsWithTupleSignal1(int value, const std::tuple<int, double, QString> &t)
|
||||||
|
{
|
||||||
|
emit multiArgsWithTupleSignal1(value, t);
|
||||||
|
}
|
||||||
|
void emitMultiArgsWithTupleSignal2(const std::tuple<int, double, QString> &t, int value)
|
||||||
|
{
|
||||||
|
emit multiArgsWithTupleSignal2(t, value);
|
||||||
|
}
|
||||||
|
void emitMultiArgsWithPairSignal1(int value, const std::pair<int, double> &p)
|
||||||
|
{
|
||||||
|
emit multiArgsWithPairSignal1(value, p);
|
||||||
|
}
|
||||||
|
void emitMultiArgsWithPairSignal2(const std::pair<int, double> &p, int value)
|
||||||
|
{
|
||||||
|
emit multiArgsWithPairSignal2(p, value);
|
||||||
|
}
|
||||||
|
|
||||||
void emitNoArgPrivateSignal() { emit noArgPrivateSignal(QPrivateSignal()); }
|
void emitNoArgPrivateSignal() { emit noArgPrivateSignal(QPrivateSignal()); }
|
||||||
void emitIntArgPrivateSignal(int value) { emit intArgPrivateSignal(value, QPrivateSignal()); }
|
void emitIntArgPrivateSignal(int value) { emit intArgPrivateSignal(value, QPrivateSignal()); }
|
||||||
@ -71,17 +88,51 @@ public:
|
|||||||
{
|
{
|
||||||
emit multiArgsPrivateSignal(value1, value2, value3, QPrivateSignal());
|
emit multiArgsPrivateSignal(value1, value2, value3, QPrivateSignal());
|
||||||
}
|
}
|
||||||
|
void emitTupleArgPrivateSignal(const std::tuple<int, double, QString> &t)
|
||||||
|
{
|
||||||
|
emit tupleArgPrivateSignal(t, QPrivateSignal());
|
||||||
|
}
|
||||||
|
void emitMultiArgsWithTuplePrivateSignal1(int value, const std::tuple<int, double, QString> &t)
|
||||||
|
{
|
||||||
|
emit multiArgsWithTuplePrivateSignal1(value, t, QPrivateSignal());
|
||||||
|
}
|
||||||
|
void emitMultiArgsWithTuplePrivateSignal2(const std::tuple<int, double, QString> &t, int value)
|
||||||
|
{
|
||||||
|
emit multiArgsWithTuplePrivateSignal2(t, value, QPrivateSignal());
|
||||||
|
}
|
||||||
|
void emitMultiArgsWithPairPrivateSignal1(int value, const std::pair<int, double> &p)
|
||||||
|
{
|
||||||
|
emit multiArgsWithPairPrivateSignal1(value, p, QPrivateSignal());
|
||||||
|
}
|
||||||
|
void emitMultiArgsWithPairPrivateSignal2(const std::pair<int, double> &p, int value)
|
||||||
|
{
|
||||||
|
emit multiArgsWithPairPrivateSignal2(p, value, QPrivateSignal());
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void noArgSignal();
|
void noArgSignal();
|
||||||
void intArgSignal(int value);
|
void intArgSignal(int value);
|
||||||
void constRefArg(const QString &value);
|
void constRefArg(const QString &value);
|
||||||
void multipleArgs(int value1, double value2, const QString &value3);
|
void multipleArgs(int value1, double value2, const QString &value3);
|
||||||
|
void tupleArgSignal(const std::tuple<int, double, QString> &t);
|
||||||
|
void multiArgsWithTupleSignal1(int value, const std::tuple<int, double, QString> &t);
|
||||||
|
void multiArgsWithTupleSignal2(const std::tuple<int, double, QString> &t, int value);
|
||||||
|
void multiArgsWithPairSignal1(int value, const std::pair<int, double> &p);
|
||||||
|
void multiArgsWithPairSignal2(const std::pair<int, double> &p, int value);
|
||||||
|
|
||||||
// Private signals
|
// Private signals
|
||||||
void noArgPrivateSignal(QPrivateSignal);
|
void noArgPrivateSignal(QPrivateSignal);
|
||||||
void intArgPrivateSignal(int value, QPrivateSignal);
|
void intArgPrivateSignal(int value, QPrivateSignal);
|
||||||
void multiArgsPrivateSignal(int value1, double value2, const QString &value3, QPrivateSignal);
|
void multiArgsPrivateSignal(int value1, double value2, const QString &value3, QPrivateSignal);
|
||||||
|
void tupleArgPrivateSignal(const std::tuple<int, double, QString> &t, QPrivateSignal);
|
||||||
|
void multiArgsWithTuplePrivateSignal1(int value, const std::tuple<int, double, QString> &t,
|
||||||
|
QPrivateSignal);
|
||||||
|
void multiArgsWithTuplePrivateSignal2(const std::tuple<int, double, QString> &t, int value,
|
||||||
|
QPrivateSignal);
|
||||||
|
void multiArgsWithPairPrivateSignal1(int value, const std::pair<int, double> &p,
|
||||||
|
QPrivateSignal);
|
||||||
|
void multiArgsWithPairPrivateSignal2(const std::pair<int, double> &p, int value,
|
||||||
|
QPrivateSignal);
|
||||||
};
|
};
|
||||||
|
|
||||||
class LambdaThread : public QThread
|
class LambdaThread : public QThread
|
||||||
@ -3492,6 +3543,16 @@ void tst_QFuture::canceledFutureIsNotValid()
|
|||||||
|
|
||||||
void tst_QFuture::signalConnect()
|
void tst_QFuture::signalConnect()
|
||||||
{
|
{
|
||||||
|
const int intValue = 42;
|
||||||
|
const double doubleValue = 42.5;
|
||||||
|
const QString stringValue = "42";
|
||||||
|
|
||||||
|
using TupleType = std::tuple<int, double, QString>;
|
||||||
|
const TupleType tuple(intValue, doubleValue, stringValue);
|
||||||
|
|
||||||
|
using PairType = std::pair<int, double>;
|
||||||
|
const PairType pair(intValue, doubleValue);
|
||||||
|
|
||||||
// No arg
|
// No arg
|
||||||
{
|
{
|
||||||
SenderObject sender;
|
SenderObject sender;
|
||||||
@ -3525,16 +3586,66 @@ void tst_QFuture::signalConnect()
|
|||||||
// Multiple args
|
// Multiple args
|
||||||
{
|
{
|
||||||
SenderObject sender;
|
SenderObject sender;
|
||||||
using TupleArgs = std::tuple<int, double, QString>;
|
|
||||||
auto future =
|
auto future =
|
||||||
QtFuture::connect(&sender, &SenderObject::multipleArgs).then([](TupleArgs values) {
|
QtFuture::connect(&sender, &SenderObject::multipleArgs).then([](TupleType values) {
|
||||||
return values;
|
return values;
|
||||||
});
|
});
|
||||||
sender.emitMultipleArgs(42, 42.5, "42");
|
sender.emitMultipleArgs(intValue, doubleValue, stringValue);
|
||||||
auto result = future.result();
|
auto result = future.result();
|
||||||
QCOMPARE(std::get<0>(result), 42);
|
QCOMPARE(result, tuple);
|
||||||
QCOMPARE(std::get<1>(result), 42.5);
|
}
|
||||||
QCOMPARE(std::get<2>(result), "42");
|
|
||||||
|
// Single std::tuple arg
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<TupleType> future = QtFuture::connect(&sender, &SenderObject::tupleArgSignal);
|
||||||
|
sender.emitTupleArgSignal(tuple);
|
||||||
|
auto result = future.result();
|
||||||
|
QCOMPARE(result, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-args signal(int, std::tuple)
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<std::tuple<int, TupleType>> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::multiArgsWithTupleSignal1);
|
||||||
|
sender.emitMultiArgsWithTupleSignal1(142, tuple);
|
||||||
|
const auto [v, t] = future.result();
|
||||||
|
QCOMPARE(v, 142);
|
||||||
|
QCOMPARE(t, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-args signal(std::tuple, int)
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<std::tuple<TupleType, int>> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::multiArgsWithTupleSignal2);
|
||||||
|
sender.emitMultiArgsWithTupleSignal2(tuple, 142);
|
||||||
|
const auto [t, v] = future.result();
|
||||||
|
QCOMPARE(v, 142);
|
||||||
|
QCOMPARE(t, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-args signal(int, std::pair)
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<std::tuple<int, PairType>> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::multiArgsWithPairSignal1);
|
||||||
|
sender.emitMultiArgsWithPairSignal1(142, pair);
|
||||||
|
const auto [v, p] = future.result();
|
||||||
|
QCOMPARE(v, 142);
|
||||||
|
QCOMPARE(p, pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-args signal(std::pair, int)
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<std::tuple<PairType, int>> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::multiArgsWithPairSignal2);
|
||||||
|
sender.emitMultiArgsWithPairSignal2(pair, 142);
|
||||||
|
const auto [p, v] = future.result();
|
||||||
|
QCOMPARE(v, 142);
|
||||||
|
QCOMPARE(p, pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No arg private signal
|
// No arg private signal
|
||||||
@ -3562,12 +3673,64 @@ void tst_QFuture::signalConnect()
|
|||||||
{
|
{
|
||||||
SenderObject sender;
|
SenderObject sender;
|
||||||
auto future = QtFuture::connect(&sender, &SenderObject::multiArgsPrivateSignal)
|
auto future = QtFuture::connect(&sender, &SenderObject::multiArgsPrivateSignal)
|
||||||
.then([](std::tuple<int, double, QString> values) { return values; });
|
.then([](TupleType values) { return values; });
|
||||||
sender.emitMultiArgsPrivateSignal(42, 42.5, "42");
|
sender.emitMultiArgsPrivateSignal(intValue, doubleValue, stringValue);
|
||||||
const auto [i, d, s] = future.result();
|
auto result = future.result();
|
||||||
QCOMPARE(i, 42);
|
QCOMPARE(result, tuple);
|
||||||
QCOMPARE(d, 42.5);
|
}
|
||||||
QCOMPARE(s, "42");
|
|
||||||
|
// Single std::tuple arg private signal
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<TupleType> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::tupleArgPrivateSignal);
|
||||||
|
sender.emitTupleArgPrivateSignal(tuple);
|
||||||
|
auto result = future.result();
|
||||||
|
QCOMPARE(result, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-args private signal(int, std::tuple)
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<std::tuple<int, TupleType>> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::multiArgsWithTuplePrivateSignal1);
|
||||||
|
sender.emitMultiArgsWithTuplePrivateSignal1(142, tuple);
|
||||||
|
const auto [v, t] = future.result();
|
||||||
|
QCOMPARE(v, 142);
|
||||||
|
QCOMPARE(t, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-args private signal(std::tuple, int)
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<std::tuple<TupleType, int>> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::multiArgsWithTuplePrivateSignal2);
|
||||||
|
sender.emitMultiArgsWithTuplePrivateSignal2(tuple, 142);
|
||||||
|
const auto [t, v] = future.result();
|
||||||
|
QCOMPARE(v, 142);
|
||||||
|
QCOMPARE(t, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-args private signal(int, std::pair)
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<std::tuple<int, PairType>> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::multiArgsWithPairPrivateSignal1);
|
||||||
|
sender.emitMultiArgsWithPairPrivateSignal1(142, pair);
|
||||||
|
const auto [v, p] = future.result();
|
||||||
|
QCOMPARE(v, 142);
|
||||||
|
QCOMPARE(p, pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-args private signal(std::pair, int)
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
QFuture<std::tuple<PairType, int>> future =
|
||||||
|
QtFuture::connect(&sender, &SenderObject::multiArgsWithPairPrivateSignal2);
|
||||||
|
sender.emitMultiArgsWithPairPrivateSignal2(pair, 142);
|
||||||
|
const auto [p, v] = future.result();
|
||||||
|
QCOMPARE(v, 142);
|
||||||
|
QCOMPARE(p, pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sender destroyed
|
// Sender destroyed
|
||||||
|
Loading…
x
Reference in New Issue
Block a user