summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNils Jeisecke <nils.jeisecke@saltation.com>2018-03-02 16:57:11 +0100
committerNils Jeisecke <nils.jeisecke@saltation.com>2018-03-10 06:12:24 +0000
commitfee8944cbe2a976e1b4a71c5df048e84a0bc6db0 (patch)
tree210fe33464d31b577f92a078faa2fed738540788
parentb767c7363f7ceda88553fb8abb6d4cb70b70bd2f (diff)
Allow use of template class instances inheriting from a Q_GADGET in Qml
The Q_GADGET macro cannot be used in templates. It can however be useful to derive a template class from a Q_GADGET enabled base class to benefit from type safety features in C++ (e.g. the class could represent an id or handle for some C++ type). For proper wrapping of a QVariant with a gadget value in a QJSValue, the QMetaType::IsGadget flag must be set for the registered template instance type - which does not happen prior to the fix because IsGadgetHelper requires qt_check_for_QGADGET_macro to be defined in the registered class but not in an ancestor class - in other words: The class must declare Q_GADGET. To overcome this, IsGadgetHelper/IsPointerToGadgetHelper can now differentiate between a Q_GADGET flagged class (allowing automatic registration) and a derived class, e.g. a template class (forcing Q_DECLARE_METATYPE to be used explicitly). [ChangeLog][QtCore][QMetaObject] It is now possible to use template class instances inheriting from a Q_GADGET in Qml Task-number: QTBUG-66744 Change-Id: I7632ad45cff79fa422b3f852ca0b963f35fab155 Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
-rw-r--r--src/corelib/kernel/qmetatype.h26
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp19
2 files changed, 35 insertions, 10 deletions
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 455d0350e0..4674efe568 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -1381,7 +1381,7 @@ namespace QtPrivate
};
template<typename T, typename Enable = void>
- struct IsGadgetHelper { enum { Value = false }; };
+ struct IsGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
template<typename T>
struct IsGadgetHelper<T, typename T::QtGadgetHelper>
@@ -1389,11 +1389,14 @@ namespace QtPrivate
template <typename X>
static char checkType(void (X::*)());
static void *checkType(void (T::*)());
- enum { Value = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *) };
+ enum {
+ IsRealGadget = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
+ IsGadgetOrDerivedFrom = true
+ };
};
template<typename T, typename Enable = void>
- struct IsPointerToGadgetHelper { enum { Value = false }; };
+ struct IsPointerToGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
template<typename T>
struct IsPointerToGadgetHelper<T*, typename T::QtGadgetHelper>
@@ -1402,7 +1405,10 @@ namespace QtPrivate
template <typename X>
static char checkType(void (X::*)());
static void *checkType(void (T::*)());
- enum { Value = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *) };
+ enum {
+ IsRealGadget = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
+ IsGadgetOrDerivedFrom = true
+ };
};
@@ -1435,12 +1441,12 @@ namespace QtPrivate
static inline const QMetaObject *value() { return &T::staticMetaObject; }
};
template<typename T>
- struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::Value>::type>
+ struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
{
static inline const QMetaObject *value() { return &T::staticMetaObject; }
};
template<typename T>
- struct MetaObjectForType<T, typename QEnableIf<IsPointerToGadgetHelper<T>::Value>::Type>
+ struct MetaObjectForType<T, typename std::enable_if<IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
{
static inline const QMetaObject *value() { return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject; }
};
@@ -1599,8 +1605,8 @@ namespace QtPrivate
template <typename T, int =
QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
- QtPrivate::IsGadgetHelper<T>::Value ? QMetaType::IsGadget :
- QtPrivate::IsPointerToGadgetHelper<T>::Value ? QMetaType::PointerToGadget :
+ QtPrivate::IsGadgetHelper<T>::IsRealGadget ? QMetaType::IsGadget :
+ QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget :
QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0>
struct QMetaTypeIdQObject
{
@@ -1653,8 +1659,8 @@ namespace QtPrivate {
| (IsWeakPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::WeakPointerToQObject : 0)
| (IsTrackingPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::TrackingPointerToQObject : 0)
| (std::is_enum<T>::value ? QMetaType::IsEnumeration : 0)
- | (IsGadgetHelper<T>::Value ? QMetaType::IsGadget : 0)
- | (IsPointerToGadgetHelper<T>::Value ? QMetaType::PointerToGadget : 0)
+ | (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0)
+ | (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0)
};
};
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
index cc628ee26e..c6fd5d17c2 100644
--- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
+++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
@@ -141,6 +141,14 @@ public:
class CustomNonQObject {};
class GadgetDerived : public CustomGadget {};
+// cannot use Q_GADGET due to moc limitations but wants to behave like
+// a Q_GADGET in Qml land
+template<typename T>
+class GadgetDerivedAndTyped : public CustomGadget {};
+
+Q_DECLARE_METATYPE(GadgetDerivedAndTyped<int>)
+Q_DECLARE_METATYPE(GadgetDerivedAndTyped<int>*)
+
void tst_QMetaType::defined()
{
QCOMPARE(int(QMetaTypeId2<QString>::Defined), 1);
@@ -157,6 +165,10 @@ void tst_QMetaType::defined()
QVERIFY(!QMetaTypeId2<CustomNonQObject>::Defined);
QVERIFY(!QMetaTypeId2<CustomNonQObject*>::Defined);
QVERIFY(!QMetaTypeId2<CustomGadget_NonDefaultConstructible>::Defined);
+
+ // registered with Q_DECLARE_METATYPE
+ QVERIFY(QMetaTypeId2<GadgetDerivedAndTyped<int>>::Defined);
+ QVERIFY(QMetaTypeId2<GadgetDerivedAndTyped<int>*>::Defined);
}
struct Bar
@@ -396,6 +408,10 @@ void tst_QMetaType::typeName_data()
QTest::newRow("CustomGadget*") << ::qMetaTypeId<CustomGadget*>() << QString::fromLatin1("CustomGadget*");
QTest::newRow("CustomQObject::CustomQEnum") << ::qMetaTypeId<CustomQObject::CustomQEnum>() << QString::fromLatin1("CustomQObject::CustomQEnum");
QTest::newRow("Qt::ArrowType") << ::qMetaTypeId<Qt::ArrowType>() << QString::fromLatin1("Qt::ArrowType");
+
+ // template instance class derived from Q_GADGET enabled class
+ QTest::newRow("GadgetDerivedAndTyped<int>") << ::qMetaTypeId<GadgetDerivedAndTyped<int>>() << QString::fromLatin1("GadgetDerivedAndTyped<int>");
+ QTest::newRow("GadgetDerivedAndTyped<int>*") << ::qMetaTypeId<GadgetDerivedAndTyped<int>*>() << QString::fromLatin1("GadgetDerivedAndTyped<int>*");
}
void tst_QMetaType::typeName()
@@ -1703,6 +1719,9 @@ void tst_QMetaType::metaObject_data()
QTest::newRow("MyGadget*") << ::qMetaTypeId<MyGadget*>() << &MyGadget::staticMetaObject << false << true << false;
QTest::newRow("MyEnum") << ::qMetaTypeId<MyGadget::MyEnum>() << &MyGadget::staticMetaObject << false << false << false;
QTest::newRow("Qt::ScrollBarPolicy") << ::qMetaTypeId<Qt::ScrollBarPolicy>() << &QObject::staticQtMetaObject << false << false << false;
+
+ QTest::newRow("GadgetDerivedAndTyped<int>") << ::qMetaTypeId<GadgetDerivedAndTyped<int>>() << &GadgetDerivedAndTyped<int>::staticMetaObject << true << false << false;
+ QTest::newRow("GadgetDerivedAndTyped<int>*") << ::qMetaTypeId<GadgetDerivedAndTyped<int>*>() << &GadgetDerivedAndTyped<int>::staticMetaObject << false << true << false;
}