diff options
author | Olivier Goffart <ogoffart@woboq.com> | 2012-11-03 18:17:59 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2012-11-06 18:43:14 +0100 |
commit | 029cc40c2ac2f6f1013020f6af5e63b46a7a8317 (patch) | |
tree | 4adf821002592864d57b71d7a1162848ff4a9aa2 | |
parent | 202bfbceda8b22da40810ada0c42ecf37083c9f7 (diff) |
Allow connect to functors with less parameters than the signal
Before, the functor slot (or lambda expression) had to have the same amount
of arguments as the signal.
This shown to be a big problem to be able to connect to signals that had
a QPrivateSlot.
This implementation use the type of the operator() of the functor to
know how many arguments we have.
As a bonus, we also can check the arguments in a static assert.
The test comes from https://codereview.qt-project.org/#change,38703
But this patch also works without variadic template
If the compiler does not support decltype, we workaround the lack of it
by using another level of indirection.
Change-Id: I9850b43e8caf77356a2ec3f4c0b0ed532d96029e
Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
-rw-r--r-- | src/corelib/kernel/qobject.h | 20 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 36 |
2 files changed, 55 insertions, 1 deletions
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 689946b6c4..e9316c98f0 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -279,10 +279,28 @@ public: static inline typename QtPrivate::QEnableIf<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::Type connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot) { +#ifndef Q_COMPILER_DECLTYPE //Workaround the lack of decltype using another function as indirection + return connect_functor(sender, signal, slot, &Func2::operator()); } + template <typename Func1, typename Func2, typename Func2Operator> + static inline QMetaObject::Connection connect_functor(const QObject *sender, Func1 signal, Func2 slot, Func2Operator) { + typedef QtPrivate::FunctionPointer<Func2Operator> SlotType ; +#else + + typedef QtPrivate::FunctionPointer<decltype(&Func2::operator())> SlotType ; +#endif typedef QtPrivate::FunctionPointer<Func1> SignalType; + Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), + "The slot requires more arguments than the signal provides."); + Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value), + "Signal and slot arguments are not compatible."); + Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value), + "Return type of the slot is not compatible with the return type of the signal."); + return connectImpl(sender, reinterpret_cast<void **>(&signal), sender, 0, - new QtPrivate::QFunctorSlotObject<Func2, SignalType::ArgumentCount, typename SignalType::Arguments, typename SignalType::ReturnType>(slot), + new QtPrivate::QFunctorSlotObject<Func2, SlotType::ArgumentCount, + typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, + typename SignalType::ReturnType>(slot), Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject); } #endif //Q_QDOC diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index f48f86cceb..c340d00361 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -140,6 +140,7 @@ private slots: void returnValue2_data(); void returnValue2(); void connectVirtualSlots(); + void connectFunctorArgDifference(); }; class SenderObject : public QObject @@ -5484,5 +5485,40 @@ void tst_QObject::connectVirtualSlots() */ } +struct SlotFunctor +{ + void operator()() {} +}; + +struct SlotFunctorString +{ + void operator()(const QString &) {} +}; + +void tst_QObject::connectFunctorArgDifference() +{ + QTimer timer; + // Compile-time tests that the connection is successful. + connect(&timer, &QTimer::timeout, SlotFunctor()); + connect(&timer, &QTimer::objectNameChanged, SlotFunctorString()); + connect(qApp, &QCoreApplication::aboutToQuit, SlotFunctor()); + + connect(&timer, &QTimer::objectNameChanged, SlotFunctor()); + QStringListModel model; + connect(&model, &QStringListModel::rowsInserted, SlotFunctor()); + +#if defined(Q_COMPILER_LAMBDA) + connect(&timer, &QTimer::timeout, [=](){}); + connect(&timer, &QTimer::objectNameChanged, [=](const QString &){}); + connect(qApp, &QCoreApplication::aboutToQuit, [=](){}); + + connect(&timer, &QTimer::objectNameChanged, [=](){}); + connect(&model, &QStringListModel::rowsInserted, [=](){}); + connect(&model, &QStringListModel::rowsInserted, [=](const QModelIndex &){}); +#endif + + QVERIFY(true); +} + QTEST_MAIN(tst_QObject) #include "tst_qobject.moc" |