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>
This commit is contained in:
parent
b767c7363f
commit
fee8944cbe
@ -1381,7 +1381,7 @@ namespace QtPrivate
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename Enable = void>
|
template<typename T, typename Enable = void>
|
||||||
struct IsGadgetHelper { enum { Value = false }; };
|
struct IsGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsGadgetHelper<T, typename T::QtGadgetHelper>
|
struct IsGadgetHelper<T, typename T::QtGadgetHelper>
|
||||||
@ -1389,11 +1389,14 @@ namespace QtPrivate
|
|||||||
template <typename X>
|
template <typename X>
|
||||||
static char checkType(void (X::*)());
|
static char checkType(void (X::*)());
|
||||||
static void *checkType(void (T::*)());
|
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>
|
template<typename T, typename Enable = void>
|
||||||
struct IsPointerToGadgetHelper { enum { Value = false }; };
|
struct IsPointerToGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsPointerToGadgetHelper<T*, typename T::QtGadgetHelper>
|
struct IsPointerToGadgetHelper<T*, typename T::QtGadgetHelper>
|
||||||
@ -1402,7 +1405,10 @@ namespace QtPrivate
|
|||||||
template <typename X>
|
template <typename X>
|
||||||
static char checkType(void (X::*)());
|
static char checkType(void (X::*)());
|
||||||
static void *checkType(void (T::*)());
|
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; }
|
static inline const QMetaObject *value() { return &T::staticMetaObject; }
|
||||||
};
|
};
|
||||||
template<typename T>
|
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; }
|
static inline const QMetaObject *value() { return &T::staticMetaObject; }
|
||||||
};
|
};
|
||||||
template<typename T>
|
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; }
|
static inline const QMetaObject *value() { return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject; }
|
||||||
};
|
};
|
||||||
@ -1599,8 +1605,8 @@ namespace QtPrivate
|
|||||||
|
|
||||||
template <typename T, int =
|
template <typename T, int =
|
||||||
QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
|
QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
|
||||||
QtPrivate::IsGadgetHelper<T>::Value ? QMetaType::IsGadget :
|
QtPrivate::IsGadgetHelper<T>::IsRealGadget ? QMetaType::IsGadget :
|
||||||
QtPrivate::IsPointerToGadgetHelper<T>::Value ? QMetaType::PointerToGadget :
|
QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget :
|
||||||
QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0>
|
QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0>
|
||||||
struct QMetaTypeIdQObject
|
struct QMetaTypeIdQObject
|
||||||
{
|
{
|
||||||
@ -1653,8 +1659,8 @@ namespace QtPrivate {
|
|||||||
| (IsWeakPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::WeakPointerToQObject : 0)
|
| (IsWeakPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::WeakPointerToQObject : 0)
|
||||||
| (IsTrackingPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::TrackingPointerToQObject : 0)
|
| (IsTrackingPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::TrackingPointerToQObject : 0)
|
||||||
| (std::is_enum<T>::value ? QMetaType::IsEnumeration : 0)
|
| (std::is_enum<T>::value ? QMetaType::IsEnumeration : 0)
|
||||||
| (IsGadgetHelper<T>::Value ? QMetaType::IsGadget : 0)
|
| (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0)
|
||||||
| (IsPointerToGadgetHelper<T>::Value ? QMetaType::PointerToGadget : 0)
|
| (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,6 +141,14 @@ public:
|
|||||||
class CustomNonQObject {};
|
class CustomNonQObject {};
|
||||||
class GadgetDerived : public CustomGadget {};
|
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()
|
void tst_QMetaType::defined()
|
||||||
{
|
{
|
||||||
QCOMPARE(int(QMetaTypeId2<QString>::Defined), 1);
|
QCOMPARE(int(QMetaTypeId2<QString>::Defined), 1);
|
||||||
@ -157,6 +165,10 @@ void tst_QMetaType::defined()
|
|||||||
QVERIFY(!QMetaTypeId2<CustomNonQObject>::Defined);
|
QVERIFY(!QMetaTypeId2<CustomNonQObject>::Defined);
|
||||||
QVERIFY(!QMetaTypeId2<CustomNonQObject*>::Defined);
|
QVERIFY(!QMetaTypeId2<CustomNonQObject*>::Defined);
|
||||||
QVERIFY(!QMetaTypeId2<CustomGadget_NonDefaultConstructible>::Defined);
|
QVERIFY(!QMetaTypeId2<CustomGadget_NonDefaultConstructible>::Defined);
|
||||||
|
|
||||||
|
// registered with Q_DECLARE_METATYPE
|
||||||
|
QVERIFY(QMetaTypeId2<GadgetDerivedAndTyped<int>>::Defined);
|
||||||
|
QVERIFY(QMetaTypeId2<GadgetDerivedAndTyped<int>*>::Defined);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Bar
|
struct Bar
|
||||||
@ -396,6 +408,10 @@ void tst_QMetaType::typeName_data()
|
|||||||
QTest::newRow("CustomGadget*") << ::qMetaTypeId<CustomGadget*>() << QString::fromLatin1("CustomGadget*");
|
QTest::newRow("CustomGadget*") << ::qMetaTypeId<CustomGadget*>() << QString::fromLatin1("CustomGadget*");
|
||||||
QTest::newRow("CustomQObject::CustomQEnum") << ::qMetaTypeId<CustomQObject::CustomQEnum>() << QString::fromLatin1("CustomQObject::CustomQEnum");
|
QTest::newRow("CustomQObject::CustomQEnum") << ::qMetaTypeId<CustomQObject::CustomQEnum>() << QString::fromLatin1("CustomQObject::CustomQEnum");
|
||||||
QTest::newRow("Qt::ArrowType") << ::qMetaTypeId<Qt::ArrowType>() << QString::fromLatin1("Qt::ArrowType");
|
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()
|
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("MyGadget*") << ::qMetaTypeId<MyGadget*>() << &MyGadget::staticMetaObject << false << true << false;
|
||||||
QTest::newRow("MyEnum") << ::qMetaTypeId<MyGadget::MyEnum>() << &MyGadget::staticMetaObject << false << false << 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("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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user