diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 164 | ||||
-rw-r--r-- | src/corelib/kernel/qobject.h | 101 | ||||
-rw-r--r-- | src/corelib/kernel/qobject_impl.h | 354 | ||||
-rw-r--r-- | src/corelib/kernel/qobject_p.h | 11 | ||||
-rw-r--r-- | src/corelib/kernel/qobjectdefs.h | 4 |
5 files changed, 624 insertions, 10 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 59282d3464..e8735d0c09 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -923,9 +923,13 @@ QObject::~QObject() QObjectPrivate::Connection::~Connection() { - int *v = argumentTypes.load(); - if (v != &DIRECT_CONNECTION_ONLY) - delete [] v; + if (ownArgumentTypes) { + const int *v = argumentTypes.load(); + if (v != &DIRECT_CONNECTION_ONLY) + delete [] v; + } + if (isSlotObject && !slotObj->ref.deref()) + delete slotObj; } @@ -3022,6 +3026,7 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, i c->method_relative = method_index; c->method_offset = method_offset; c->connectionType = type; + c->isSlotObject = false; c->argumentTypes.store(types); c->nextConnectionList = 0; c->callFunction = callFunction; @@ -3231,7 +3236,7 @@ void QMetaObject::connectSlotsByName(QObject *o) static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv) { - int *argumentTypes = c->argumentTypes.load(); + const int *argumentTypes = c->argumentTypes.load(); if (!argumentTypes && argumentTypes != &DIRECT_CONNECTION_ONLY) { QMetaMethod m = sender->metaObject()->method(signal); argumentTypes = queuedConnectionTypes(m.parameterTypes()); @@ -3392,7 +3397,12 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign } const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction; const int method_relative = c->method_relative; - if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { + if (c->isSlotObject) { + QExplicitlySharedDataPointer<QObject::QSlotObjectBase> obj(c->slotObj); + locker.unlock(); + obj->call(receiver, argv ? argv : empty_argv); + locker.relock(); + } else if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { //we compare the vtable to make sure we are not in the destructor of the object. locker.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) @@ -4043,6 +4053,146 @@ void qDeleteInEventHandler(QObject *o) } /*! + \fn QMetaObject::Connection QObject::connect(const QObject *sender, (T::*signal)(...), const QObject *receiver, (T::*method)(...), Qt::ConnectionType type) + + \threadsafe + + Creates a connection of the given \a type from the \a signal in + the \a sender object to the \a method in the \a receiver object. + Returns a handle to the connection that can be used to disconnect + it later. + + The signal must be a function declared as a signal in the header. + The slot function can be any member function that can be connected + to the signal. + A slot can be connected to a given signal if the signal has at + least as many arguments as the slot, and there is an implicit + conversion between the types of the corresponding arguments in the + signal and the slot. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 44 + + This example ensures that the label always displays the current + line edit text. + + A signal can be connected to many slots and signals. Many signals + can be connected to one slot. + + If a signal is connected to several slots, the slots are activated + in the same order as the order the connection was made, when the + signal is emitted + + The function returns an handle to a connection if it successfully + connects the signal to the slot. The Connection handle will be invalid + if it cannot create the connection, for example, if QObject is unable + to verify the existence of \a signal (if it was not declared as a signal) + You can check if the QMetaObject::Connection is valid by casting it to a bool. + + The optional \a type parameter describes the type of connection + to establish. In particular, it determines whether a particular + signal is delivered to a slot immediately or queued for delivery + at a later time. If the signal is queued, the parameters must be + of types that are known to Qt's meta-object system, because Qt + needs to copy the arguments to store them in an event behind the + scenes. If you try to use a queued connection and get the error + message + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 25 + + make sure to declare the argument type with Q_DECLARE_METATYPE + + A signal is emitted for every connection you make; + two signals are emitted for duplicate connections. + This overload does not support the type Qt::UniqueConnection + */ + + +/*! + \fn QMetaObject::Connection QObject::connect(const QObject *sender, (T::*signal)(...), Functor functor) + + \threadsafe + \overload + + Creates a connection of the given \a type from the \a signal in + the \a sender object to the \a functor and returns a handle to the connection + + The signal must be a function declared as a signal in the header. + The slot function can be any function or functor that can be connected + to the signal. + A function can be connected to a given signal if the signal as at + least as many argument as the slot. A functor can be connected to a signal + if they have exactly the same number of arguments. There must exist implicit + conversion between the types of the corresponding arguments in the + signal and the slot. + + Example: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 45 + + If your compiler support C++11 lambda expressions, you can use them: + + \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 46 + + The connection will automatically disconnect if the sender is destroyed. + */ +QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal, const QObject *receiver, QObject::QSlotObjectBase *slotObj, + Qt::ConnectionType type, const int* types, const QMetaObject* senderMetaObject) +{ + int signal_index = -1; + void *args[] = { &signal_index, signal }; + senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args); + if (signal_index < 0 || signal_index >= QMetaObjectPrivate::get(senderMetaObject)->signalCount) { + qWarning("QObject::connect: signal not found in %s", senderMetaObject->className()); + return QMetaObject::Connection(0); + } + int signalOffset, methodOffset; + computeOffsets(senderMetaObject, &signalOffset, &methodOffset); + signal_index += signalOffset; + + // duplicated from QMetaObjectPrivate::connect + QObject *s = const_cast<QObject *>(sender); + QObject *r = const_cast<QObject *>(receiver); + + QOrderedMutexLocker locker(signalSlotLock(sender), + signalSlotLock(receiver)); + + if (type & Qt::UniqueConnection) { + qWarning() << "QObject::connect: Qt::UniqueConnection not supported when connecting function pointers"; + type = static_cast<Qt::ConnectionType>(type & (Qt::UniqueConnection - 1)); + } + + QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection); + c->sender = s; + c->receiver = r; + c->slotObj = slotObj; + c->connectionType = type; + c->isSlotObject = true; + if (types) { + c->argumentTypes.store(types); + c->ownArgumentTypes = false; + } + + QObjectPrivate::get(s)->addConnection(signal_index, c.data()); + + c->prev = &(QObjectPrivate::get(r)->senders); + c->next = *c->prev; + *c->prev = c.data(); + if (c->next) + c->next->prev = &c->next; + + QObjectPrivate *const sender_d = QObjectPrivate::get(s); + if (signal_index < 0) { + sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0; + } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) { + sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f)); + } + + return QMetaObject::Connection(c.take()); +} + +/*! Disconnect a connection. If the \a connection is invalid or has already been disconnected, do nothing @@ -4119,6 +4269,10 @@ QMetaObject::Connection::~Connection() the signal or the slot, or if the arguments do not match. */ +QObject::QSlotObjectBase::~QSlotObjectBase() +{ +} + QT_END_NAMESPACE #include "moc_qobject.cpp" 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, diff --git a/src/corelib/kernel/qobject_impl.h b/src/corelib/kernel/qobject_impl.h new file mode 100644 index 0000000000..7d3dc1659b --- /dev/null +++ b/src/corelib/kernel/qobject_impl.h @@ -0,0 +1,354 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q_QDOC + +#ifndef QOBJECT_H +#error Do not include qobject_impl.h directly +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +namespace QtPrivate { + template <typename T> struct RemoveRef { typedef T Type; }; + template <typename T> struct RemoveRef<const T&> { typedef T Type; }; + template <typename T> struct RemoveRef<T&> { typedef T Type; }; + template <typename T> struct RemoveConstRef { typedef T Type; }; + template <typename T> struct RemoveConstRef<const T&> { typedef T Type; }; + + /* + The following List classes are used to help to handle the list of arguments. + It follow the same principles as the lisp lists. + List_Left<L,N> take a list and a number as a parametter and returns (via the Value typedef, + the list composed of the first N element of the list + */ +#ifndef Q_COMPILER_VARIADIC_TEMPLATES + template <typename Head, typename Tail> struct List { typedef Head Car; typedef Tail Cdr; }; + template <typename L, int N> struct List_Left { typedef List<typename L::Car, typename List_Left<typename L::Cdr, N - 1>::Value > Value; }; + template <typename L> struct List_Left<L,0> { typedef void Value; }; +#else + // With variadic template, lists are represented using a variadic template argument instead of the lisp way + template <typename...> struct List {}; + template <typename Head, typename... Tail> struct List<Head, Tail...> { typedef Head Car; typedef List<Tail...> Cdr; }; + template <typename, typename> struct List_Append; + template <typename... L1, typename...L2> struct List_Append<List<L1...>, List<L2...>> { typedef List<L1..., L2...> Value; }; + template <typename L, int N> struct List_Left { + typedef typename List_Append<List<typename L::Car>,typename List_Left<typename L::Cdr, N - 1>::Value>::Value Value; + }; + template <typename L> struct List_Left<L, 0> { typedef List<> Value; }; +#endif + // List_Select<L,N> returns (via typedef Value) the Nth element of the list L + template <typename L, int N> struct List_Select { typedef typename List_Select<typename L::Cdr, N - 1>::Value Value; }; + template <typename L> struct List_Select<L,0> { typedef typename L::Car Value; }; + + /* + trick to set the return value of a slot that works even if the signal or the slot returns void + to be used like function(), ApplyReturnValue<ReturnType>(&return_value) + if function() returns a value, the operator,(T, ApplyReturnValue<ReturnType>) is called, but if it + returns void, the builtin one is used without an error. + */ + template <typename T> + struct ApplyReturnValue { + void *data; + ApplyReturnValue(void *data) : data(data) {} + }; + template<typename T, typename U> + void operator,(const T &value, const ApplyReturnValue<U> &container) { + *reinterpret_cast<U*>(container.data) = value; + } +#ifdef Q_COMPILER_RVALUE_REFS + template<typename T, typename U> + void operator,(T &&value, const ApplyReturnValue<U> &container) { + *reinterpret_cast<U*>(container.data) = value; + } +#endif + template<typename T> + void operator,(T, const ApplyReturnValue<void> &) {} + + + /* + The FunctionPointer<Func> struct is a type trait for function pointer. + - ArgumentCount is the number of argument, or -1 if it is unknown + - the Object typedef is the Object of a pointer to member function + - the Arguments typedef is the list of argument (in a QtPrivate::List) + - the Function typedef is an alias to the template parametter Func + - the call<Args, R>(f,o,args) method is used to call that slot + Args is the list of argument of the signal + R is the return type of the signal + f is the function pointer + o is the receiver object + and args is the array of pointer to arguments, as used in qt_metacall + + The Functor<Func,N> struct is the helper to call a functor of N argument. + its call function is the same as the FunctionPointer::call function. + */ +#ifndef Q_COMPILER_VARIADIC_TEMPLATES + template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1}; }; + template<class Obj, typename Ret> struct FunctionPointer<Ret (Obj::*) ()> + { + typedef Obj Object; + typedef void Arguments; + typedef Ret ReturnType; + typedef Ret (Obj::*Function) (); + enum {ArgumentCount = 0}; + template <typename Args, typename R> + static void call(Function f, Obj *o, void **arg) { (o->*f)(), ApplyReturnValue<R>(arg[0]); } + }; + template<class Obj, typename Ret, typename Arg1> struct FunctionPointer<Ret (Obj::*) (Arg1)> + { + typedef Obj Object; + typedef List<Arg1, void> Arguments; + typedef Ret ReturnType; + typedef Ret (Obj::*Function) (Arg1); + enum {ArgumentCount = 1}; + template <typename Args, typename R> + static void call(Function f, Obj *o, void **arg) { + (o->*f)((*reinterpret_cast<typename RemoveRef<typename Args::Car>::Type *>(arg[1]))), ApplyReturnValue<R>(arg[0]); + } + }; + template<class Obj, typename Ret, typename Arg1, typename Arg2> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2)> + { + typedef Obj Object; + typedef List<Arg1, List<Arg2, void> > Arguments; + typedef Ret ReturnType; + typedef Ret (Obj::*Function) (Arg1, Arg2); + enum {ArgumentCount = 2}; + template <typename Args, typename R> + static void call(Function f, Obj *o, void **arg) { + (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2])), ApplyReturnValue<R>(arg[0]); + } + }; + template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3)> + { + typedef Obj Object; + typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments; + typedef Ret ReturnType; + typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3); + enum {ArgumentCount = 3}; + template <typename Args, typename R> + static void call(Function f, Obj *o, void **arg) { + (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3])), ApplyReturnValue<R>(arg[0]); + } + }; + + template<typename Ret> struct FunctionPointer<Ret (*) ()> + { + typedef void Arguments; + typedef Ret (*Function) (); + typedef Ret ReturnType; + enum {ArgumentCount = 0}; + template <typename Args, typename R> + static void call(Function f, void *, void **arg) { f(), ApplyReturnValue<R>(arg[0]); } + }; + template<typename Ret, typename Arg1> struct FunctionPointer<Ret (*) (Arg1)> + { + typedef List<Arg1, void> Arguments; + typedef Ret ReturnType; + typedef Ret (*Function) (Arg1); + enum {ArgumentCount = 1}; + template <typename Args, typename R> + static void call(Function f, void *, void **arg) + { f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1])), ApplyReturnValue<R>(arg[0]); } + }; + template<typename Ret, typename Arg1, typename Arg2> struct FunctionPointer<Ret (*) (Arg1, Arg2)> + { + typedef List<Arg1, List<Arg2, void> > Arguments; + typedef Ret ReturnType; + typedef Ret (*Function) (Arg1, Arg2); + enum {ArgumentCount = 2}; + template <typename Args, typename R> + static void call(Function f, void *, void **arg) { + f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2])), ApplyReturnValue<R>(arg[0]); } + }; + template<typename Ret, typename Arg1, typename Arg2, typename Arg3> struct FunctionPointer<Ret (*) (Arg1, Arg2, Arg3)> + { + typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments; + typedef Ret ReturnType; + typedef Ret (*Function) (Arg1, Arg2, Arg3); + enum {ArgumentCount = 3}; + template <typename Args, typename R> + static void call(Function f, void *, void **arg) { + f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3])), ApplyReturnValue<R>(arg[0]); + } + }; + + template<typename F, int N> struct Functor; + template<typename Function> struct Functor<Function, 0> + { + template <typename Args, typename R> + static void call(Function &f, void *, void **arg) { f(), ApplyReturnValue<R>(arg[0]); } + }; + template<typename Function> struct Functor<Function, 1> + { + template <typename Args, typename R> + static void call(Function &f, void *, void **arg) { + f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1])), ApplyReturnValue<R>(arg[0]); + } + }; + template<typename Function> struct Functor<Function, 2> + { + template <typename Args, typename R> + static void call(Function &f, void *, void **arg) { + f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2])), ApplyReturnValue<R>(arg[0]); + } + }; + template<typename Function> struct Functor<Function, 3> + { + template <typename Args, typename R> + static void call(Function &f, void *, void **arg) { + f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), + *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[4])), ApplyReturnValue<R>(arg[0]); + } + }; +#else + template <int...> struct IndexesList {}; + template <typename IndexList, int Right> struct IndexesAppend; + template <int... Left, int Right> struct IndexesAppend<IndexesList<Left...>, Right> + { typedef IndexesList<Left..., Right> Value; }; + template <int N> struct Indexes + { typedef typename IndexesAppend<typename Indexes<N - 1>::Value, N - 1>::Value Value; }; + template <> struct Indexes<0> { typedef IndexesList<> Value; }; + template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1}; }; + + template <typename, typename, typename, typename> struct FunctorCall; + template <int... I, typename... SignalArgs, typename R, typename Function> + struct FunctorCall<IndexesList<I...>, List<SignalArgs...>, R, Function> { + static void call(Function f, void **arg) { + f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[I+1]))...), ApplyReturnValue<R>(arg[0]); + } + }; + template <int... I, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj> + struct FunctorCall<IndexesList<I...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> { + static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg) { + (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[I+1]))...), ApplyReturnValue<R>(arg[0]); + } + }; + + template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...)> + { + typedef Obj Object; + typedef List<Args...> Arguments; + typedef Ret ReturnType; + typedef Ret (Obj::*Function) (Args...); + enum {ArgumentCount = sizeof...(Args)}; + template <typename SignalArgs, typename R> + static void call(Function f, Obj *o, void **arg) { + FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg); + } + }; + + template<typename Ret, typename... Args> struct FunctionPointer<Ret (*) (Args...)> + { + typedef List<Args...> Arguments; + typedef Ret ReturnType; + typedef Ret (*Function) (Args...); + enum {ArgumentCount = sizeof...(Args)}; + template <typename SignalArgs, typename R> + static void call(Function f, void *, void **arg) { + FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg); + } + }; + + template<typename Function, int N> struct Functor + { + template <typename SignalArgs, typename R> + static void call(Function &f, void *, void **arg) { + FunctorCall<typename Indexes<N>::Value, SignalArgs, R, Function>::call(f, arg); + } + }; +#endif + + /* + Logic that check if the arguments of the slot matches the argument of the signal. + To be used like this: + CheckCompatibleArguments<FunctionPointer<Signal>::Arguments, FunctionPointer<Slot>::Arguments>::IncompatibleSignalSlotArguments + The IncompatibleSignalSlotArguments type do not exist if the argument are incompatible and can + then produce error message. + */ + template<typename T, bool B> struct CheckCompatibleArgumentsHelper {}; + template<typename T> struct CheckCompatibleArgumentsHelper<T, true> : T {}; + template<typename A1, typename A2> struct AreArgumentsCompatible { + static int test(A2); + static char test(...); + static A2 dummy(); + enum { value = sizeof(test(dummy())) == sizeof(int) }; + }; + template<typename A1, typename A2> struct AreArgumentsCompatible<A1, A2&> { enum { value = false }; }; + template<typename A> struct AreArgumentsCompatible<A&, A&> { enum { value = true }; }; + +#ifndef Q_COMPILER_VARIADIC_TEMPLATES + template <typename List1, typename List2> struct CheckCompatibleArguments{}; + template <> struct CheckCompatibleArguments<void, void> { typedef bool IncompatibleSignalSlotArguments; }; + template <typename List1> struct CheckCompatibleArguments<List1, void> { typedef bool IncompatibleSignalSlotArguments; }; + template <typename Arg1, typename Arg2, typename Tail1, typename Tail2> struct CheckCompatibleArguments<List<Arg1, Tail1>, List<Arg2, Tail2> > + : CheckCompatibleArgumentsHelper<CheckCompatibleArguments<Tail1, Tail2>, AreArgumentsCompatible< + typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value > {}; +#else + template <typename List1, typename List2> struct CheckCompatibleArguments{}; + template <> struct CheckCompatibleArguments<List<>, List<>> { typedef bool IncompatibleSignalSlotArguments; }; + template <typename List1> struct CheckCompatibleArguments<List1, List<>> { typedef bool IncompatibleSignalSlotArguments; }; + template <typename Arg1, typename Arg2, typename... Tail1, typename... Tail2> + struct CheckCompatibleArguments<List<Arg1, Tail1...>, List<Arg2, Tail2...>> + : CheckCompatibleArgumentsHelper<CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>, AreArgumentsCompatible< + typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value > {}; + +#endif + +} + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 2a9334ae8f..72cf5a8cca 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -114,18 +114,23 @@ public: { QObject *sender; QObject *receiver; - StaticMetaCallFunction callFunction; + union { + StaticMetaCallFunction callFunction; + QObject::QSlotObjectBase *slotObj; + }; // The next pointer for the singly-linked ConnectionList Connection *nextConnectionList; //senders linked list Connection *next; Connection **prev; - QAtomicPointer<int> argumentTypes; + QAtomicPointer<const int> argumentTypes; QAtomicInt ref_; ushort method_offset; ushort method_relative; ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking - Connection() : nextConnectionList(0), ref_(2) { + ushort isSlotObject : 1; + ushort ownArgumentTypes : 1; + Connection() : nextConnectionList(0), ref_(2), ownArgumentTypes(true) { //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection } ~Connection(); diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 1ad24387e0..ce5a924e23 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -66,10 +66,10 @@ class QString; # define QT_NO_EMIT # else # define slots -# define signals protected +# define signals public # endif # define Q_SLOTS -# define Q_SIGNALS protected +# define Q_SIGNALS public # define Q_PRIVATE_SLOT(d, signature) # define Q_EMIT #ifndef QT_NO_EMIT |