summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject.h
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@woboq.com>2011-11-23 15:06:30 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-25 01:12:14 +0100
commit583c55b243d9894d93d32fbe15bece2a9beb1d10 (patch)
treedb6237144cfb511cac1468bf851cf66639a84367 /src/corelib/kernel/qobject.h
parent79f675a1e0f628bbc25345ebc1eb1f5809166c6b (diff)
New QObject connection syntax
In addition to the old connection syntax, you can now connect using function pointers. connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue ); You can connect also to functor or C++11 lambdas The connections are now type safe (no more problems with namespaces or typedefs). Implicit type conversion is also supported. The new syntax forces us to change the meaning of signal form protected to public, in order to be able to access the signal's address everywhere The way it works is by introducing new overload of QObject::connect that take function pointer as parametter. Those new overload are template function, that are implemented inline. The actual implementation is in QObject::connectImpl which take a QObject::QSlotObject* as parametter for the slot. That slot object contains a virtual function which call the slot which has to be implemented in the header as it depends on the template parametter. So the internals of QObjectPrivate::Connection will store this QObjectSlot* in order to be able to make the call. You can read a full description here: http://developer.qt.nokia.com/wiki/New_Signal_Slot_Syntax History of commits before it was imported on gerrit: https://qt.gitorious.org/~ogoffart/qt/ogoffarts-qtbase/commits/qobject_connect_ptr Thread on the mailing list: http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-August/000796.html http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-September/001248.html (The discussions on the mailing list were about trying to find a solution that do not need making signals public, but no user friendly solution was found) Note: support for QueuedConnection, and the symetric QObject::disconnect is added in another commit. Qt::UniqueConnection is not supported yet in the new overload. Change-Id: I67d08436b0720e7f2992be9f7e34770960fa58fa Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qobject.h')
-rw-r--r--src/corelib/kernel/qobject.h101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 038b59042b..93448b5ad1 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -52,6 +52,9 @@
#include <QtCore/qcoreevent.h>
#endif
#include <QtCore/qscopedpointer.h>
+#include <QtCore/qmetatype.h>
+
+#include <QtCore/qobject_impl.h>
QT_BEGIN_HEADER
@@ -204,6 +207,58 @@ public:
inline QMetaObject::Connection connect(const QObject *sender, const char *signal,
const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;
+ //Connect a signal to a pointer to qobject member function
+ template <typename Func1, typename Func2>
+ static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
+ const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
+ Qt::ConnectionType type = Qt::AutoConnection)
+ {
+ typedef QtPrivate::FunctionPointer<Func1> SignalType;
+ typedef QtPrivate::FunctionPointer<Func2> SlotType;
+ reinterpret_cast<typename SignalType::Object *>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<typename SignalType::Object *>(0));
+
+ //compilation error if the arguments does not match.
+ typedef typename QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::IncompatibleSignalSlotArguments EnsureCompatibleArguments;
+
+ const int *types = 0;
+ return connectImpl(sender, reinterpret_cast<void **>(&signal),
+ receiver, new QSlotObject<Func2,
+ typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
+ typename SignalType::ReturnType>(slot),
+ type, types, &SignalType::Object::staticMetaObject);
+ }
+
+ //connect to a function pointer (not a member)
+ template <typename Func1, typename Func2>
+ static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::Type
+ connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
+ {
+ typedef QtPrivate::FunctionPointer<Func1> SignalType;
+ typedef QtPrivate::FunctionPointer<Func2> SlotType;
+
+ //compilation error if the arguments does not match.
+ typedef typename QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::IncompatibleSignalSlotArguments EnsureCompatibleArguments;
+ typedef typename QtPrivate::QEnableIf<(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount))>::Type EnsureArgumentsCount;
+
+ return connectImpl(sender, reinterpret_cast<void **>(&signal), sender,
+ new QStaticSlotObject<Func2,
+ typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
+ typename SignalType::ReturnType>(slot),
+ Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
+ }
+
+ //connect to a functor
+ template <typename Func1, typename Func2>
+ 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)
+ {
+ typedef QtPrivate::FunctionPointer<Func1> SignalType;
+
+ return connectImpl(sender, reinterpret_cast<void **>(&signal),
+ sender, new QFunctorSlotObject<Func2, SignalType::ArgumentCount, typename SignalType::Arguments, typename SignalType::ReturnType>(slot),
+ Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
+ }
+
static bool disconnect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member);
static bool disconnect(const QObject *sender, const QMetaMethod &signal,
@@ -273,6 +328,52 @@ protected:
private:
Q_DISABLE_COPY(QObject)
Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))
+
+ private:
+ // internal base class (interface) containing functions required to call a slot managed by a pointer to function.
+ struct QSlotObjectBase {
+ QAtomicInt ref;
+ QSlotObjectBase() : ref(1) {}
+ virtual ~QSlotObjectBase();
+ virtual void call(QObject *receiver, void **a) = 0;
+ };
+ // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject
+ // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
+ template<typename Func, typename Args, typename R> struct QSlotObject : QSlotObjectBase
+ {
+ typedef QtPrivate::FunctionPointer<Func> FuncType;
+ Func function;
+ QSlotObject(Func f) : function(f) {};
+ virtual void call(QObject *receiver, void **a) {
+ FuncType::template call<Args, R>(function, static_cast<typename FuncType::Object *>(receiver), a);
+ }
+ };
+ // implementation of QSlotObjectBase for which the slot is a static function
+ // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
+ template<typename Func, typename Args, typename R> struct QStaticSlotObject : QSlotObjectBase
+ {
+ typedef QtPrivate::FunctionPointer<Func> FuncType;
+ Func function;
+ QStaticSlotObject(Func f) : function(f) {}
+ virtual void call(QObject *receiver, void **a) {
+ FuncType::template call<Args, R>(function, receiver, a);
+ }
+ };
+ // implementation of QSlotObjectBase for which the slot is a functor (or lambda)
+ // N is the number of arguments
+ // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
+ template<typename Func, int N, typename Args, typename R> struct QFunctorSlotObject : QSlotObjectBase
+ {
+ typedef QtPrivate::Functor<Func, N> FuncType;
+ Func function;
+ QFunctorSlotObject(const Func &f) : function(f) {}
+ virtual void call(QObject *receiver, void **a) {
+ FuncType::template call<Args, R>(function, receiver, a);
+ }
+ };
+
+ static QMetaObject::Connection connectImpl(const QObject *sender, void **signal, const QObject *receiver, QSlotObjectBase *slot,
+ Qt::ConnectionType type, const int *types, const QMetaObject *senderMetaObject);
};
inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,