summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qobject.h34
-rw-r--r--src/corelib/kernel/qobjectdefs_impl.h36
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp126
3 files changed, 190 insertions, 6 deletions
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 7beaa32855..aaa09fac50 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -265,27 +266,50 @@ 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)
{
+#if defined (Q_COMPILER_DECLTYPE) && defined (Q_COMPILER_VARIADIC_TEMPLATES)
+ typedef QtPrivate::FunctionPointer<Func1> SignalType;
+ const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;
+
+ Q_STATIC_ASSERT_X((FunctorArgumentCount >= 0),
+ "Signal and slot arguments are not compatible.");
+ const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
+ typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
+#else
+ // Without variadic template, we don't detect the best overload of operator(). We just
+ // assume there is only one simple operator() and connect to &Func2::operator()
+
+ /* If you get an error such as:
+ couldn't deduce template parameter 'Func2Operator'
+ or
+ cannot resolve address of overloaded function
+ It means the functor does not have a single operator().
+ Functors with overloaded or templated operator() are only supported if the compiler supports
+ C++11 variadic templates
+ */
#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;
+ typedef typename SlotType::ReturnType SlotReturnType;
+ const int SlotArgumentCount = SlotType::ArgumentCount;
- Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
+ Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= SlotArgumentCount,
"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),
+#endif
+
+ Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<SlotReturnType, 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, SlotType::ArgumentCount,
- typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
+ new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
+ typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
}
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h
index 46a6eab253..4f44d9204e 100644
--- a/src/corelib/kernel/qobjectdefs_impl.h
+++ b/src/corelib/kernel/qobjectdefs_impl.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -597,10 +598,43 @@ namespace QtPrivate {
enum { value = AreArgumentsCompatible<typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value
&& CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value };
};
+#endif
+
+#if defined(Q_COMPILER_DECLTYPE) && defined(Q_COMPILER_VARIADIC_TEMPLATES)
+ /*
+ Find the maximum number of arguments a functor object can take and be still compatible with
+ the arguments from the signal.
+ Value is the number of arguments, or -1 if nothing matches.
+ */
+ template <typename Functor, typename ArgList> struct ComputeFunctorArgumentCount;
+
+ template <typename Functor, typename ArgList, bool Done> struct ComputeFunctorArgumentCountHelper
+ { enum { Value = -1 }; };
+ template <typename Functor, typename First, typename... ArgList>
+ struct ComputeFunctorArgumentCountHelper<Functor, List<First, ArgList...>, false>
+ : ComputeFunctorArgumentCount<Functor,
+ typename List_Left<List<First, ArgList...>, sizeof...(ArgList)>::Value> {};
+
+ template <typename Functor, typename... ArgList> struct ComputeFunctorArgumentCount<Functor, List<ArgList...>>
+ {
+ template <typename D> static D dummy();
+ template <typename F> static auto test(F f) -> decltype(((f.operator()((dummy<ArgList>())...)), int()));
+ static char test(...);
+ enum {
+ Ok = sizeof(test(dummy<Functor>())) == sizeof(int),
+ Value = Ok ? sizeof...(ArgList) : int(ComputeFunctorArgumentCountHelper<Functor, List<ArgList...>, Ok>::Value)
+ };
+ };
+ /* get the return type of a functor, given the signal argument list */
+ template <typename Functor, typename ArgList> struct FunctorReturnType;
+ template <typename Functor, typename ... ArgList> struct FunctorReturnType<Functor, List<ArgList...>> {
+ template <typename D> static D dummy();
+ typedef decltype(dummy<Functor>().operator()((dummy<ArgList>())...)) Value;
+ };
#endif
-}
+}
QT_END_NAMESPACE
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index dd88d863c9..06fc89f657 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -143,6 +143,7 @@ private slots:
void connectVirtualSlots();
void connectPrivateSlots();
void connectFunctorArgDifference();
+ void connectFunctorOverloads();
void disconnectDoesNotLeakFunctor();
};
@@ -5599,6 +5600,131 @@ void tst_QObject::connectFunctorArgDifference()
QVERIFY(true);
}
+struct ComplexFunctor {
+ ComplexFunctor(int &overload, QList<QVariant> &result) : overload(overload), result(result) {}
+ void operator()(int a, int b) {
+ overload = 1;
+ result << a << b;
+ }
+ void operator()(double a, double b) {
+ overload = 2;
+ result << a << b;
+ }
+ void operator()(const QString &s) {
+ overload = 3;
+ result << s;
+ }
+ void operator()(const QString &) const {
+ Q_ASSERT(!"Should not be called because the non-const one should");
+ overload = -1;
+ }
+ template<typename T1, typename T2, typename T3, typename T4>
+ void operator()(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) {
+ overload = 4;
+ result << QVariant::fromValue(t1) << QVariant::fromValue(t2) << QVariant::fromValue(t3) << QVariant::fromValue(t4);
+ }
+ int &overload;
+ QList<QVariant> &result;
+protected:
+ void operator()() const {
+ Q_ASSERT(!"Should not be called because it is protected");
+ overload = -1;
+ }
+};
+
+struct ComplexFunctorDeriv : ComplexFunctor {
+ ComplexFunctorDeriv(int &overload, QList<QVariant> &result) : ComplexFunctor(overload, result) {}
+
+ void operator()() const {
+ overload = 10;
+ }
+ void operator()(int a, int b) {
+ overload = 11;
+ result << a << b;
+ }
+ using ComplexFunctor::operator();
+private:
+ void operator()(int) {
+ Q_ASSERT(!"Should not be called because it is private");
+ overload = -1;
+ }
+};
+
+class FunctorArgDifferenceObject : public QObject
+{
+ Q_OBJECT
+signals:
+ void signal_ii(int,int);
+ void signal_iiS(int,int, const QString &);
+ void signal_dd(double,double);
+ void signal_ddS(double,double, const QString &);
+ void signal_S(const QString &);
+ void signal_SSSS(const QString &, const QString &, const QString &, const QString &);
+ void signal_iiSS(int, int, const QString &, const QString &);
+ void signal_VV(const QVariant &, const QVariant &);
+};
+
+template<typename Functor, typename Signal>
+void connectFunctorOverload_impl(Signal signal, int expOverload, QList<QVariant> expResult)
+{
+ FunctorArgDifferenceObject obj;
+ int overload;
+ QList<QVariant> result;
+ QVERIFY(QObject::connect(&obj, signal, Functor(overload, result)));
+
+ obj.signal_ii(1,2);
+ obj.signal_iiS(3,4,"5");
+ obj.signal_dd(6.6,7.7);
+ obj.signal_ddS(8.8,9.9,"10");
+ obj.signal_S("11");
+ obj.signal_SSSS("12", "13", "14", "15");
+ obj.signal_iiSS(16, 17, "18", "19");
+ obj.signal_VV(20,21);
+
+ QCOMPARE(overload, expOverload);
+ QCOMPARE(result, expResult);
+}
+
+void tst_QObject::connectFunctorOverloads()
+{
+#if defined (Q_COMPILER_DECLTYPE) && defined (Q_COMPILER_VARIADIC_TEMPLATES)
+ connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_ii, 1,
+ (QList<QVariant>() << 1 << 2));
+ connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_iiS, 1,
+ (QList<QVariant>() << 3 << 4));
+ connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_dd, 2,
+ (QList<QVariant>() << 6.6 << 7.7));
+ connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_ddS, 2,
+ (QList<QVariant>() << 8.8 << 9.9));
+ connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_S, 3,
+ (QList<QVariant>() << QString("11")));
+ connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_SSSS, 4,
+ (QList<QVariant>() << QString("12") << QString("13") << QString("14") << QString("15")));
+ connectFunctorOverload_impl<ComplexFunctor>(&FunctorArgDifferenceObject::signal_iiSS, 4,
+ (QList<QVariant>() << 16 << 17 << QString("18") << QString("19")));
+ connectFunctorOverload_impl<ComplexFunctorDeriv>(&FunctorArgDifferenceObject::signal_ii, 11,
+ (QList<QVariant>() << 1 << 2));
+ connectFunctorOverload_impl<ComplexFunctorDeriv>(&FunctorArgDifferenceObject::signal_iiS, 11,
+ (QList<QVariant>() << 3 << 4));
+ connectFunctorOverload_impl<ComplexFunctorDeriv>(&FunctorArgDifferenceObject::signal_dd, 2,
+ (QList<QVariant>() << 6.6 << 7.7));
+ connectFunctorOverload_impl<ComplexFunctorDeriv>(&FunctorArgDifferenceObject::signal_ddS, 2,
+ (QList<QVariant>() << 8.8 << 9.9));
+ connectFunctorOverload_impl<ComplexFunctorDeriv>(&FunctorArgDifferenceObject::signal_S, 3,
+ (QList<QVariant>() << QString("11")));
+ connectFunctorOverload_impl<ComplexFunctorDeriv>(&FunctorArgDifferenceObject::signal_SSSS, 4,
+ (QList<QVariant>() << QString("12") << QString("13") << QString("14") << QString("15")));
+ connectFunctorOverload_impl<ComplexFunctorDeriv>(&FunctorArgDifferenceObject::signal_iiSS, 4,
+ (QList<QVariant>() << 16 << 17 << QString("18") << QString("19")));
+ connectFunctorOverload_impl<ComplexFunctorDeriv>(&FunctorArgDifferenceObject::signal_VV, 10,
+ (QList<QVariant>()));
+
+
+#else
+ QSKIP("Does not compile without C++11 variadic template");
+#endif
+}
+
static int countedStructObjectsCount = 0;
struct CountedStruct
{