From eb24dfcccb304c84a147f0eafd3b3fc3df3ef4f3 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Fri, 2 Mar 2012 14:48:09 +0100 Subject: [PATCH] Add template specialization of QMetaType for QObject derived pointers. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This makes it possible to do things like QVariant::fromValue(new SomeObject); without first using Q_DECLARE_METATYPE(Something*) This functionality was originally part of http://codereview.qt-project.org/#change,11710 but was rejected because the functionality was based on specialization of QVariant::fromValue which could be dangerous. This new implementation doesn't have such danger. Change-Id: I83fe941b6984be54469bc6b9191f6eacaceaa036 Reviewed-by: Jędrzej Nowacki Reviewed-by: Olivier Goffart --- src/corelib/kernel/qmetatype.h | 75 +++++++++++++++------- .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 17 +++++ .../auto/corelib/kernel/qvariant/tst_qvariant.cpp | 15 +++++ 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index f969875..06ada13 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -364,33 +364,11 @@ void qMetaTypeLoadHelper(QDataStream &stream, void *t) template <> inline void qMetaTypeLoadHelper(QDataStream &, void *) {} #endif // QT_NO_DATASTREAM -template -struct QMetaTypeId -{ - enum { Defined = 0 }; -}; - -template -struct QMetaTypeId2 -{ - enum { Defined = QMetaTypeId::Defined }; - static inline int qt_metatype_id() { return QMetaTypeId::qt_metatype_id(); } -}; - class QObject; class QWidget; -namespace QtPrivate { - template ::Defined> - struct QMetaTypeIdHelper { - static inline int qt_metatype_id() - { return QMetaTypeId2::qt_metatype_id(); } - }; - template struct QMetaTypeIdHelper { - static inline int qt_metatype_id() - { return -1; } - }; - +namespace QtPrivate +{ template struct IsPointerToTypeDerivedFromQObject { @@ -427,6 +405,38 @@ namespace QtPrivate { Q_STATIC_ASSERT_X(sizeof(T), "Type argument of Q_DECLARE_METATYPE(T*) must be fully defined"); enum { Value = sizeof(checkType(static_cast(0))) == sizeof(yes_type) }; }; +} + +template ::Value> +struct QMetaTypeIdQObject +{ + enum { + Defined = 0 + }; +}; + +template +struct QMetaTypeId : public QMetaTypeIdQObject +{ +}; + +template +struct QMetaTypeId2 +{ + enum { Defined = QMetaTypeId::Defined }; + static inline int qt_metatype_id() { return QMetaTypeId::qt_metatype_id(); } +}; + +namespace QtPrivate { + template ::Defined> + struct QMetaTypeIdHelper { + static inline int qt_metatype_id() + { return QMetaTypeId2::qt_metatype_id(); } + }; + template struct QMetaTypeIdHelper { + static inline int qt_metatype_id() + { return -1; } + }; // Function pointers don't derive from QObject template struct IsPointerToTypeDerivedFromQObject { enum { Value = false }; }; @@ -501,6 +511,23 @@ inline int qRegisterMetaType( #endif } +template +struct QMetaTypeIdQObject +{ + enum { + Defined = 1 + }; + + static int qt_metatype_id() + { + static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); + if (!metatype_id.load()) + metatype_id.storeRelease(qRegisterMetaType(QByteArray(T::staticMetaObject.className() + QByteArrayLiteral("*")).constData(), + reinterpret_cast(quintptr(-1)))); + return metatype_id.loadAcquire(); + } +}; + #ifndef QT_NO_DATASTREAM template inline int qRegisterMetaTypeStreamOperators() diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index f8403f1..572ecc9 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -100,12 +100,29 @@ private slots: struct Foo { int i; }; + +class CustomQObject : public QObject +{ + Q_OBJECT +public: + CustomQObject(QObject *parent = 0) + : QObject(parent) + { + } +}; + +class CustomNonQObject {}; + void tst_QMetaType::defined() { QCOMPARE(int(QMetaTypeId2::Defined), 1); QCOMPARE(int(QMetaTypeId2::Defined), 0); QCOMPARE(int(QMetaTypeId2::Defined), 1); QCOMPARE(int(QMetaTypeId2::Defined), 0); + QVERIFY(QMetaTypeId2::Defined); + QVERIFY(!QMetaTypeId2::Defined); + QVERIFY(!QMetaTypeId2::Defined); + QVERIFY(!QMetaTypeId2::Defined); } struct Bar diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index ccdab17..5aa1389 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -2541,9 +2541,24 @@ public: }; Q_DECLARE_METATYPE(CustomQObjectDerived*) +class CustomQObjectDerivedNoMetaType : public CustomQObject { + Q_OBJECT +public: + CustomQObjectDerivedNoMetaType(QObject *parent = 0) : CustomQObject(parent) {} +}; + void tst_QVariant::qvariant_cast_QObject_derived() { { + CustomQObjectDerivedNoMetaType *object = new CustomQObjectDerivedNoMetaType(this); + QVariant data = QVariant::fromValue(object); + QVERIFY(data.userType() == qMetaTypeId()); + QCOMPARE(data.value(), object); + QCOMPARE(data.value(), object); + QCOMPARE(data.value(), object); + QVERIFY(data.value() == 0); + } + { CustomQObjectDerived *object = new CustomQObjectDerived(this); QVariant data = QVariant::fromValue(object); -- 2.7.4