diff options
Diffstat (limited to 'src/corelib/kernel/qmetatype.h')
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 538 |
1 files changed, 365 insertions, 173 deletions
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index c68809169c..12a67aef58 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1,43 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2018 Intel Corporation. -** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2018 Intel Corporation. +// Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QMETATYPE_H #define QMETATYPE_H @@ -46,14 +10,14 @@ #include <QtCore/qatomic.h> #include <QtCore/qbytearray.h> #include <QtCore/qcompare.h> -#include <QtCore/qvarlengtharray.h> -#include <QtCore/qrefcount.h> -#include <QtCore/qscopeguard.h> #include <QtCore/qdatastream.h> +#include <QtCore/qfloat16.h> +#include <QtCore/qhashfunctions.h> #include <QtCore/qiterable.h> #ifndef QT_NO_QOBJECT #include <QtCore/qobjectdefs.h> #endif +#include <QtCore/qscopeguard.h> #include <array> #include <new> @@ -61,6 +25,8 @@ #include <list> #include <map> #include <functional> +#include <optional> +#include <QtCore/q20type_traits.h> #ifdef Bool #error qmetatype.h must be included before any header file that defines Bool @@ -78,8 +44,7 @@ template <typename T> inline constexpr int qMetaTypeId(); // F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType) -#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\ - F(Void, 43, void) \ +#define QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F)\ F(Bool, 1, bool) \ F(Int, 2, int) \ F(UInt, 3, uint) \ @@ -99,7 +64,11 @@ inline constexpr int qMetaTypeId(); F(Nullptr, 51, std::nullptr_t) \ F(QCborSimpleType, 52, QCborSimpleType) \ -#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\ +#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \ + QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F) \ + F(Void, 43, void) \ + +#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F) \ F(VoidStar, 31, void*) \ #if QT_CONFIG(easingcurve) @@ -123,6 +92,12 @@ inline constexpr int qMetaTypeId(); #else # define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) #endif +#ifndef QT_NO_VARIANT +# define QT_FOR_EACH_STATIC_QVARIANT(F) \ + F(QVariant, 41, QVariant) +#else +# define QT_FOR_EACH_STATIC_QVARIANT(F) +#endif #define QT_FOR_EACH_STATIC_CORE_CLASS(F)\ F(QChar, 7, QChar) \ @@ -144,7 +119,7 @@ inline constexpr int qMetaTypeId(); F(QPointF, 26, QPointF) \ QT_FOR_EACH_STATIC_EASINGCURVE(F) \ F(QUuid, 30, QUuid) \ - F(QVariant, 41, QVariant) \ + QT_FOR_EACH_STATIC_QVARIANT(F) \ QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \ F(QJsonValue, 45, QJsonValue) \ F(QJsonObject, 46, QJsonObject) \ @@ -153,18 +128,26 @@ inline constexpr int qMetaTypeId(); F(QCborValue, 53, QCborValue) \ F(QCborArray, 54, QCborArray) \ F(QCborMap, 55, QCborMap) \ + F(Float16, 63, qfloat16) \ QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F) #define QT_FOR_EACH_STATIC_CORE_POINTER(F)\ F(QObjectStar, 39, QObject*) -#define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\ +#ifndef QT_NO_VARIANT +# define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\ F(QVariantMap, 8, QVariantMap) \ F(QVariantList, 9, QVariantList) \ F(QVariantHash, 28, QVariantHash) \ F(QVariantPair, 58, QVariantPair) \ F(QByteArrayList, 49, QByteArrayList) \ F(QStringList, 11, QStringList) \ + /**/ +#else +# define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\ + F(QByteArrayList, 49, QByteArrayList) \ + F(QStringList, 11, QStringList) +#endif #if QT_CONFIG(shortcut) #define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)\ @@ -218,12 +201,20 @@ inline constexpr int qMetaTypeId(); F(UInt, -1, uint, "quint32") \ F(LongLong, -1, qlonglong, "qint64") \ F(ULongLong, -1, qulonglong, "quint64") \ + F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \ + F(QStringList, -1, QStringList, "QList<QString>") \ + QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F) + +#ifndef QT_NO_VARIANT +#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F) \ F(QVariantList, -1, QVariantList, "QList<QVariant>") \ F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \ F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \ F(QVariantPair, -1, QVariantPair, "QPair<QVariant,QVariant>") \ - F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \ - F(QStringList, -1, QStringList, "QList<QString>") \ + /**/ +#else +#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F) +#endif #define QT_FOR_EACH_STATIC_TYPE(F)\ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\ @@ -259,14 +250,35 @@ struct QMetaObject; namespace QtPrivate { +class QMetaTypeInterface; + +// MSVC is the only supported compiler that includes the type of a variable in +// its mangled form, so it's not binary-compatible to drop the const in +// QMetaTypeInterfaceWrapper::metaType for it, which means we must keep the +// mutable field until Qt 7. +#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || !defined(Q_CC_MSVC) +# define QMTI_MUTABLE +using NonConstMetaTypeInterface = QMetaTypeInterface; +#else +# define QMTI_MUTABLE mutable +using NonConstMetaTypeInterface = const QMetaTypeInterface; +#endif + class QMetaTypeInterface { public: - ushort revision; // 0 in Qt 6.0. Can increase if new field are added + + /* Revision: Can increase if new field are added, or if semantics changes + 0: Initial Revision + 1: the meaning of the NeedsDestruction flag changed + */ + static inline constexpr ushort CurrentRevision = 1; + + ushort revision; ushort alignment; uint size; uint flags; - mutable QBasicAtomicInt typeId; + QMTI_MUTABLE QBasicAtomicInt typeId; using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *); MetaObjectFn metaObjectFn; @@ -295,6 +307,7 @@ public: using LegacyRegisterOp = void (*)(); LegacyRegisterOp legacyRegisterOp; }; +#undef QMTI_MUTABLE /*! This template is used for implicit conversion from type From to type To. @@ -327,14 +340,14 @@ To convertImplicit(const From& from) class Q_CORE_EXPORT QMetaType { public: -#ifndef Q_CLANG_QDOC +#ifndef Q_QDOC // The code that actually gets compiled. enum Type { // these are merged with QVariant QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID) FirstCoreType = Bool, - LastCoreType = QVariantPair, + LastCoreType = Float16, FirstGuiType = QFont, LastGuiType = QColorSpace, FirstWidgetsType = QSizePolicy, @@ -363,9 +376,10 @@ public: QByteArrayList = 49, QObjectStar = 39, SChar = 40, Void = 43, Nullptr = 51, - QVariantMap = 8, QVariantList = 9, QVariantHash = 28, + QVariantMap = 8, QVariantList = 9, QVariantHash = 28, QVariantPair = 58, QCborSimpleType = 52, QCborValue = 53, QCborArray = 54, QCborMap = 55, Char16 = 56, Char32 = 57, + Int128 = 59, UInt128 = 60, Float128 = 61, BFloat16 = 62, Float16 = 63, // Gui types QFont = 0x1000, QPixmap = 0x1001, QBrush = 0x1002, QColor = 0x1003, QPalette = 0x1004, @@ -376,8 +390,8 @@ public: // Widget types QSizePolicy = 0x2000, - LastCoreType = Char32, - LastGuiType = QColorSpace, + + // Start-point for client-code types: User = 65536 }; #endif @@ -400,6 +414,9 @@ public: IsPointer = 0x800, IsQmlList =0x1000, // used in the QML engine to recognize QQmlListProperty<T> and list<T> IsConst = 0x2000, + // since 6.5: + NeedsCopyConstruction = 0x4000, + NeedsMoveConstruction = 0x8000, }; Q_DECLARE_FLAGS(TypeFlags, TypeFlag) @@ -417,7 +434,7 @@ public: { return QMetaType(type).name(); } QT_DEPRECATED_VERSION_6_0 static int sizeOf(int type) - { return QMetaType(type).sizeOf(); } + { return int(QMetaType(type).sizeOf()); } QT_DEPRECATED_VERSION_6_0 static TypeFlags typeFlags(int type) { return QMetaType(type).flags(); } @@ -445,7 +462,12 @@ public: bool isValid() const; bool isRegistered() const; -#if QT_REMOVED_SINCE(6, 1) || defined(Q_QDOC) + void registerType() const + { + // "register" is a reserved keyword + registerHelper(); + } +#if QT_CORE_REMOVED_SINCE(6, 1) || defined(Q_QDOC) int id() const; #else // ### Qt 7: Remove traces of out of line version @@ -453,12 +475,7 @@ public: int id(int = 0) const { // keep in sync with the version in removed_api.cpp - if (d_ptr) { - if (int id = d_ptr->typeId.loadRelaxed()) - return id; - return idHelper(); - } - return 0; + return registerHelper(); } #endif constexpr qsizetype sizeOf() const; @@ -474,6 +491,10 @@ public: QPartialOrdering compare(const void *lhs, const void *rhs) const; bool equals(const void *lhs, const void *rhs) const; + bool isDefaultConstructible() const noexcept { return d_ptr && isDefaultConstructible(d_ptr); } + bool isCopyConstructible() const noexcept { return d_ptr && isCopyConstructible(d_ptr); } + bool isMoveConstructible() const noexcept { return d_ptr && isMoveConstructible(d_ptr); } + bool isDestructible() const noexcept { return d_ptr && isDestructible(d_ptr); } bool isEqualityComparable() const; bool isOrdered() const; @@ -492,26 +513,29 @@ public: #endif #endif + QMetaType underlyingType() const; + template<typename T> constexpr static QMetaType fromType(); static QMetaType fromName(QByteArrayView name); - - friend bool operator==(QMetaType a, QMetaType b) +private: + friend bool comparesEqual(const QMetaType &lhs, + const QMetaType &rhs) noexcept { - if (a.d_ptr == b.d_ptr) + if (lhs.d_ptr == rhs.d_ptr) return true; - if (!a.d_ptr || !b.d_ptr) + if (!lhs.d_ptr || !rhs.d_ptr) return false; // one type is undefined, the other is defined // avoid id call if we already have the id - const int aId = a.id(); - const int bId = b.id(); + const int aId = lhs.id(); + const int bId = rhs.id(); return aId == bId; } - friend bool operator!=(QMetaType a, QMetaType b) { return !(a == b); } - -public: - + Q_DECLARE_EQUALITY_COMPARABLE(QMetaType) #ifndef QT_NO_DEBUG_STREAM +private: + friend Q_CORE_EXPORT QDebug operator<<(QDebug d, QMetaType m); +public: bool debugStream(QDebug& dbg, const void *rhs); bool hasRegisteredDebugStreamOperator() const; @@ -611,7 +635,14 @@ public: auto converter = [function = std::move(function)](const void *from, void *to) -> bool { const From *f = static_cast<const From *>(from); To *t = static_cast<To *>(to); - *t = function(*f); + auto &&r = function(*f); + if constexpr (std::is_same_v<q20::remove_cvref_t<decltype(r)>, std::optional<To>>) { + if (!r) + return false; + *t = *std::forward<decltype(r)>(r); + } else { + *t = std::forward<decltype(r)>(r); + } return true; }; return registerConverterImpl<From, To>(std::move(converter), fromType, toType); @@ -720,7 +751,7 @@ public: static bool hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType); -#ifndef Q_CLANG_QDOC +#ifndef Q_QDOC template<typename, bool> friend struct QtPrivate::SequentialValueTypeIsMetaType; template<typename, bool> friend struct QtPrivate::AssociativeValueTypeIsMetaType; template<typename, bool> friend struct QtPrivate::IsMetaTypePair; @@ -740,7 +771,28 @@ public: const QtPrivate::QMetaTypeInterface *iface() const { return d_ptr; } private: + static bool isDefaultConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION; + static bool isCopyConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION; + static bool isMoveConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION; + static bool isDestructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION; + +#if QT_CORE_REMOVED_SINCE(6, 5) int idHelper() const; +#endif + static int registerHelper(const QtPrivate::QMetaTypeInterface *iface); + int registerHelper() const + { + // keep in sync with the QMetaType::id() version in removed_api.cpp + if (d_ptr) { + if (int id = d_ptr->typeId.loadRelaxed()) + return id; + return registerHelper(d_ptr); + } + return 0; + } + + friend int qRegisterMetaType(QMetaType meta); + friend class QVariant; const QtPrivate::QMetaTypeInterface *d_ptr = nullptr; }; @@ -821,6 +873,34 @@ QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(QT_FORWARD_DECLARE_SHARED_POINTER_T namespace QtPrivate { + namespace detail { + template<typename T, typename ODR_VIOLATION_PREVENTER> + struct is_complete_helper + { + template<typename U> + static auto check(U *) -> std::integral_constant<bool, sizeof(U) != 0>; + static auto check(...) -> std::false_type; + using type = decltype(check(static_cast<T *>(nullptr))); + }; + } // namespace detail + + template <typename T, typename ODR_VIOLATION_PREVENTER> + struct is_complete : detail::is_complete_helper<std::remove_reference_t<T>, ODR_VIOLATION_PREVENTER>::type {}; + + template <typename T> struct MetatypeDecay { using type = T; }; + template <typename T> struct MetatypeDecay<const T> { using type = T; }; + template <typename T> struct MetatypeDecay<const T &> { using type = T; }; + + template <typename T> struct IsPointerDeclaredOpaque : + std::disjunction<std::is_member_pointer<T>, + std::is_function<std::remove_pointer_t<T>>> + {}; + template <> struct IsPointerDeclaredOpaque<void *> : std::true_type {}; + template <> struct IsPointerDeclaredOpaque<const void *> : std::true_type {}; + + // Note: this does not check that T = U* isn't pointing to a + // forward-declared type. You may want to combine with + // checkTypeIsSuitableForMetaType(). template<typename T> struct IsPointerToTypeDerivedFromQObject { @@ -855,7 +935,6 @@ namespace QtPrivate static yes_type checkType(const QObject* ); #endif static no_type checkType(...); - static_assert(sizeof(T), "Type argument of Q_PROPERTY or Q_DECLARE_METATYPE(T*) must be fully defined"); enum { Value = sizeof(checkType(static_cast<T*>(nullptr))) == sizeof(yes_type) }; }; @@ -874,6 +953,9 @@ namespace QtPrivate }; }; + template <typename T> + using IsRealGadget = std::bool_constant<IsGadgetHelper<T>::IsRealGadget>; + template<typename T, typename Enable = void> struct IsPointerToGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; }; @@ -912,13 +994,6 @@ namespace QtPrivate static constexpr MetaObjectFn metaObjectFunction = nullptr; }; #ifndef QT_NO_QOBJECT - template<> - struct MetaObjectForType<void> - { - static constexpr const QMetaObject *value() { return nullptr; } - using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *); - static constexpr MetaObjectFn metaObjectFunction = nullptr; - }; template<typename T> struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> { @@ -926,7 +1001,12 @@ namespace QtPrivate static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; } }; template<typename T> - struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>::type> + struct MetaObjectForType<T, std::enable_if_t< + std::disjunction_v< + std::bool_constant<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>, + std::is_base_of<QObject, T> + > + >> { static constexpr const QMetaObject *value() { return &T::staticMetaObject; } static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; } @@ -1118,12 +1198,28 @@ namespace QtPrivate }; #endif + template <typename X> static constexpr bool checkTypeIsSuitableForMetaType() + { + using T = typename MetatypeDecay<X>::type; + static_assert(is_complete<T, void>::value || std::is_void_v<T>, + "Meta Types must be fully defined"); + static_assert(!std::is_reference_v<T>, + "Meta Types cannot be non-const references or rvalue references."); + if constexpr (std::is_pointer_v<T> && !IsPointerDeclaredOpaque<T>::value) { + using Pointed = std::remove_pointer_t<T>; + static_assert(is_complete<Pointed, void>::value, + "Pointer Meta Types must either point to fully-defined types " + "or be declared with Q_DECLARE_OPAQUE_POINTER(T *)"); + } + return true; + } + Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type); } // namespace QtPrivate template <typename T, int = QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : - QtPrivate::IsGadgetHelper<T>::IsRealGadget ? QMetaType::IsGadget : + QtPrivate::IsRealGadget<T>::value ? QMetaType::IsGadget : QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget : QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0> struct QMetaTypeIdQObject @@ -1150,7 +1246,12 @@ template <typename T> struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {}; template <typename T> -struct QMetaTypeId2<T&> { enum {Defined = false }; }; +struct QMetaTypeId2<T&> +{ + using NameAsArrayType = void; + enum { Defined = false, IsBuiltIn = false }; + static inline constexpr int qt_metatype_id() { return 0; } +}; namespace QtPrivate { template <typename T, bool Defined = QMetaTypeId2<T>::Defined> @@ -1179,8 +1280,10 @@ namespace QtPrivate { struct QMetaTypeTypeFlags { enum { Flags = (QTypeInfo<T>::isRelocatable ? QMetaType::RelocatableType : 0) - | (QTypeInfo<T>::isComplex ? QMetaType::NeedsConstruction : 0) - | (QTypeInfo<T>::isComplex ? QMetaType::NeedsDestruction : 0) + | ((!std::is_default_constructible_v<T> || !QTypeInfo<T>::isValueInitializationBitwiseZero) ? QMetaType::NeedsConstruction : 0) + | (!std::is_trivially_destructible_v<T> ? QMetaType::NeedsDestruction : 0) + | (!std::is_trivially_copy_constructible_v<T> ? QMetaType::NeedsCopyConstruction : 0) + | (!std::is_trivially_move_constructible_v<T> ? QMetaType::NeedsMoveConstruction : 0) | (IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : 0) | (IsSharedPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::SharedPointerToQObject : 0) | (IsWeakPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::WeakPointerToQObject : 0) @@ -1188,7 +1291,7 @@ namespace QtPrivate { | (IsEnumOrFlags<T>::value ? QMetaType::IsEnumeration : 0) | (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0) | (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0) - | (QTypeInfo<T>::isPointer ? QMetaType::IsPointer : 0) + | (std::is_pointer_v<T> ? QMetaType::IsPointer : 0) | (IsUnsignedEnum<T> ? QMetaType::IsUnsignedEnumeration : 0) | (IsQmlListType<T> ? QMetaType::IsQmlList : 0) | (std::is_const_v<std::remove_pointer_t<T>> ? QMetaType::IsConst : 0) @@ -1226,7 +1329,7 @@ namespace QtPrivate { } template <typename T> -int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName) +int qRegisterNormalizedMetaTypeImplementation(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName) { #ifndef QT_NO_QOBJECT Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), @@ -1254,6 +1357,39 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz return id; } +// This primary template calls the -Implementation, like all other specialisations should. +// But the split allows to +// - in a header: +// - define a specialization of this template calling an out-of-line function +// (QT_DECL_METATYPE_EXTERN{,_TAGGED}) +// - in the .cpp file: +// - define the out-of-line wrapper to call the -Implementation +// (QT_IMPL_METATYPE_EXTERN{,_TAGGED}) +// The _TAGGED variants let you choose a tag (must be a C identifier) to disambiguate +// the out-of-line function; the non-_TAGGED variants use the passed class name as tag. +template <typename T> +int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName) +{ + return qRegisterNormalizedMetaTypeImplementation<T>(normalizedTypeName); +} + +#define QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TAG, EXPORT) \ + QT_BEGIN_NAMESPACE \ + EXPORT int qRegisterNormalizedMetaType_ ## TAG (const QByteArray &); \ + template <> inline int qRegisterNormalizedMetaType< TYPE >(const QByteArray &name) \ + { return qRegisterNormalizedMetaType_ ## TAG (name); } \ + QT_END_NAMESPACE \ + Q_DECLARE_METATYPE(TYPE) \ + /* end */ +#define QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TAG) \ + int qRegisterNormalizedMetaType_ ## TAG (const QByteArray &name) \ + { return qRegisterNormalizedMetaTypeImplementation< TYPE >(name); } \ + /* end */ +#define QT_DECL_METATYPE_EXTERN(TYPE, EXPORT) \ + QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TYPE, EXPORT) +#define QT_IMPL_METATYPE_EXTERN(TYPE) \ + QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TYPE) + template <typename T> int qRegisterMetaType(const char *typeName) { @@ -1269,6 +1405,9 @@ template <typename T> inline constexpr int qMetaTypeId() { if constexpr (bool(QMetaTypeId2<T>::IsBuiltIn)) { + // this has the same result as the below code, but avoids asking the + // compiler to load a global variable whose value we know at compile + // time return QMetaTypeId2<T>::MetaType; } else { return QMetaType::fromType<T>().id(); @@ -1282,6 +1421,11 @@ inline constexpr int qRegisterMetaType() return id; } +inline int qRegisterMetaType(QMetaType meta) +{ + return meta.registerHelper(); +} + #ifndef QT_NO_QOBJECT template <typename T> struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject> @@ -1292,7 +1436,7 @@ struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject> static int qt_metatype_id() { - static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); + Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) return id; const char *const cName = T::staticMetaObject.className(); @@ -1314,7 +1458,7 @@ struct QMetaTypeIdQObject<T, QMetaType::IsGadget> static int qt_metatype_id() { - static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); + Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) return id; const char *const cName = T::staticMetaObject.className(); @@ -1333,7 +1477,7 @@ struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget> static int qt_metatype_id() { - static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); + Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) return id; const char *const cName = T::staticMetaObject.className(); @@ -1355,7 +1499,7 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> static int qt_metatype_id() { - static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); + Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); if (const int id = metatype_id.loadAcquire()) return id; const char *eName = qt_getEnumName(T()); @@ -1372,11 +1516,8 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> #define Q_DECLARE_OPAQUE_POINTER(POINTER) \ QT_BEGIN_NAMESPACE namespace QtPrivate { \ - template <> \ - struct IsPointerToTypeDerivedFromQObject<POINTER > \ - { \ - enum { Value = false }; \ - }; \ + template <> struct IsPointerDeclaredOpaque<POINTER> \ + : std::true_type {}; \ } QT_END_NAMESPACE \ /**/ @@ -1388,9 +1529,10 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> struct QMetaTypeId< TYPE > \ { \ enum { Defined = 1 }; \ + static_assert(QtPrivate::checkTypeIsSuitableForMetaType<TYPE>()); \ static int qt_metatype_id() \ { \ - static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ + Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ if (const int id = metatype_id.loadAcquire()) \ return id; \ constexpr auto arr = QtPrivate::typenameHelper<TYPE>(); \ @@ -1438,7 +1580,7 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \ }; \ static int qt_metatype_id() \ { \ - static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ + Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ if (const int id = metatype_id.loadRelaxed()) \ return id; \ const char *tName = QMetaType::fromType<T>().name(); \ @@ -1466,7 +1608,7 @@ struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \ }; \ static int qt_metatype_id() \ { \ - static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ + Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ if (const int id = metatype_id.loadAcquire()) \ return id; \ const char *tName = QMetaType::fromType<T>().name(); \ @@ -1514,7 +1656,7 @@ struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \ }; \ static int qt_metatype_id() \ { \ - static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ + Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ if (const int id = metatype_id.loadAcquire()) \ return id; \ const char * const cName = T::staticMetaObject.className(); \ @@ -1529,7 +1671,7 @@ struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \ }; \ template<typename T> \ struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \ - typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> \ + typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value && !std::is_const_v<T>>::type> \ { \ static bool registerConverter() \ { \ @@ -1608,11 +1750,19 @@ QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE) QT_BEGIN_NAMESPACE +namespace QtPrivate { +// out-of-line helpers to reduce template code bloat ("SCARY") and improve compile times: +Q_CORE_EXPORT bool hasRegisteredConverterFunctionToPairVariantInterface(QMetaType m); +Q_CORE_EXPORT bool hasRegisteredConverterFunctionToIterableMetaSequence(QMetaType m); +Q_CORE_EXPORT bool hasRegisteredMutableViewFunctionToIterableMetaSequence(QMetaType m); +Q_CORE_EXPORT bool hasRegisteredConverterFunctionToIterableMetaAssociation(QMetaType m); +Q_CORE_EXPORT bool hasRegisteredMutableViewFunctionToIterableMetaAssociation(QMetaType m); +} + template <typename T> inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter() { - const QMetaType to = QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>(); - if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) { + if (!QtPrivate::hasRegisteredConverterFunctionToPairVariantInterface(QMetaType::fromType<T>())) { QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o; return QMetaType::registerConverter<T, QtMetaTypePrivate::QPairVariantInterfaceImpl>(o); } @@ -1644,8 +1794,7 @@ struct SequentialValueTypeIsMetaType<T, true> { static bool registerConverter() { - const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>(); - if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) { + if (!QtPrivate::hasRegisteredConverterFunctionToIterableMetaSequence(QMetaType::fromType<T>())) { QSequentialIterableConvertFunctor<T> o; return QMetaType::registerConverter<T, QIterable<QMetaSequence>>(o); } @@ -1654,8 +1803,7 @@ struct SequentialValueTypeIsMetaType<T, true> static bool registerMutableView() { - const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>(); - if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) { + if (!QtPrivate::hasRegisteredMutableViewFunctionToIterableMetaSequence(QMetaType::fromType<T>())) { QSequentialIterableMutableViewFunctor<T> o; return QMetaType::registerMutableView<T, QIterable<QMetaSequence>>(o); } @@ -1688,8 +1836,7 @@ struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T { static bool registerConverter() { - const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>(); - if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) { + if (!QtPrivate::hasRegisteredConverterFunctionToIterableMetaAssociation(QMetaType::fromType<T>())) { QAssociativeIterableConvertFunctor<T> o; return QMetaType::registerConverter<T, QIterable<QMetaAssociation>>(o); } @@ -1698,8 +1845,7 @@ struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T static bool registerMutableView() { - const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>(); - if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) { + if (!QtPrivate::hasRegisteredMutableViewFunctionToIterableMetaAssociation(QMetaType::fromType<T>())) { QAssociativeIterableMutableViewFunctor<T> o; return QMetaType::registerMutableView<T, QIterable<QMetaAssociation>>(o); } @@ -1733,7 +1879,7 @@ private: #ifdef Q_CC_MSVC /// On MSVC, keywords like class or struct are not separated with spaces in constexpr /// context - if (msvcKw) + if (msvcKw && !is_ident_char(*b)) return true; #endif Q_UNUSED(msvcKw); @@ -2114,6 +2260,7 @@ struct is_std_pair<std::pair<T1_, T2_>> : std::true_type { using T2 = T2_; }; +namespace TypeNameHelper { template<typename T> constexpr auto typenameHelper() { @@ -2154,23 +2301,25 @@ constexpr auto typenameHelper() #ifdef QT_NAMESPACE QT_STRINGIFY(QT_NAMESPACE) "::" #endif -#ifdef Q_CC_MSVC - "auto __cdecl QtPrivate::typenameHelper<" +#if defined(Q_CC_MSVC) && defined(Q_CC_CLANG) + "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper(void) [T = " +#elif defined(Q_CC_MSVC) + "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper<" #elif defined(Q_CC_CLANG) - "auto QtPrivate::typenameHelper() [T = " + "auto QtPrivate::TypeNameHelper::typenameHelper() [T = " #elif defined(Q_CC_GHS) - "auto QtPrivate::typenameHelper<T>() [with T=" + "auto QtPrivate::TypeNameHelper::typenameHelper<T>()[with T=" #else - "constexpr auto QtPrivate::typenameHelper() [with T = " + "constexpr auto QtPrivate::TypeNameHelper::typenameHelper() [with T = " #endif ) - 1; -#ifdef Q_CC_MSVC +#if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) constexpr int suffix = sizeof(">(void)"); #else constexpr int suffix = sizeof("]"); #endif -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) && Q_CC_GNU < 804) +#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU_ONLY < 804 auto func = Q_FUNC_INFO; const char *begin = func + prefix; const char *end = func + sizeof(Q_FUNC_INFO) - suffix; @@ -2187,6 +2336,8 @@ constexpr auto typenameHelper() return result; } } +} // namespace TypeNameHelper +using TypeNameHelper::typenameHelper; template<typename T, typename = void> struct BuiltinMetaType : std::integral_constant<int, 0> @@ -2243,28 +2394,45 @@ struct QDebugStreamOperatorForType <T, false> template<typename T, bool = QTypeTraits::has_stream_operator_v<QDataStream, T>> struct QDataStreamOperatorForType { + static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr; + static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr; +}; + +#ifndef QT_NO_DATASTREAM +template<typename T> +struct QDataStreamOperatorForType <T, true> +{ static void dataStreamOut(const QMetaTypeInterface *, QDataStream &ds, const void *a) { ds << *reinterpret_cast<const T *>(a); } static void dataStreamIn(const QMetaTypeInterface *, QDataStream &ds, void *a) { ds >> *reinterpret_cast<T *>(a); } }; +#endif -template<typename T> -struct QDataStreamOperatorForType <T, false> -{ - static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr; - static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr; -}; +// Performance optimization: +// +// Don't add all these symbols to the dynamic symbol tables on ELF systems and +// on Darwin. Each library is going to have a copy anyway and QMetaType already +// copes with some of these being "hidden" (see QMetaType::idHelper()). We may +// as well let the linker know it can always use the local copy. +// +// This is currently not enabled for GCC due to +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106023 + +#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG) +# pragma GCC visibility push(hidden) +#endif template<typename S> class QMetaTypeForType { public: static constexpr decltype(typenameHelper<S>()) name = typenameHelper<S>(); + static constexpr unsigned Flags = QMetaTypeTypeFlags<S>::Flags; static constexpr QMetaTypeInterface::DefaultCtrFn getDefaultCtr() { - if constexpr (std::is_default_constructible_v<S>) { + if constexpr (std::is_default_constructible_v<S> && !QTypeInfo<S>::isValueInitializationBitwiseZero) { return [](const QMetaTypeInterface *, void *addr) { new (addr) S(); }; } else { return nullptr; @@ -2273,7 +2441,7 @@ public: static constexpr QMetaTypeInterface::CopyCtrFn getCopyCtr() { - if constexpr (std::is_copy_constructible_v<S>) { + if constexpr (std::is_copy_constructible_v<S> && !std::is_trivially_copy_constructible_v<S>) { return [](const QMetaTypeInterface *, void *addr, const void *other) { new (addr) S(*reinterpret_cast<const S *>(other)); }; @@ -2284,7 +2452,7 @@ public: static constexpr QMetaTypeInterface::MoveCtrFn getMoveCtr() { - if constexpr (std::is_move_constructible_v<S>) { + if constexpr (std::is_move_constructible_v<S> && !std::is_trivially_move_constructible_v<S>) { return [](const QMetaTypeInterface *, void *addr, void *other) { new (addr) S(std::move(*reinterpret_cast<S *>(other))); }; @@ -2325,11 +2493,17 @@ public: template<typename T> struct QMetaTypeInterfaceWrapper { - static inline constexpr const QMetaTypeInterface metaType = { - /*.revision=*/ 0, + // if the type ID for T is known at compile-time, then we can declare + // the QMetaTypeInterface object const; otherwise, we declare it as + // non-const and the .typeId is updated by QMetaType::idHelper(). + static constexpr bool IsConstMetaTypeInterface = !!BuiltinMetaType<T>::value; + using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>; + + static inline InterfaceType metaType = { + /*.revision=*/ QMetaTypeInterface::CurrentRevision, /*.alignment=*/ alignof(T), /*.size=*/ sizeof(T), - /*.flags=*/ QMetaTypeTypeFlags<T>::Flags, + /*.flags=*/ QMetaTypeForType<T>::Flags, /*.typeId=*/ BuiltinMetaType<T>::value, /*.metaObjectFn=*/ MetaObjectForType<T>::metaObjectFunction, /*.name=*/ QMetaTypeForType<T>::getName(), @@ -2346,6 +2520,9 @@ struct QMetaTypeInterfaceWrapper }; }; +#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG) +# pragma GCC visibility pop +#endif template<> class QMetaTypeInterfaceWrapper<void> @@ -2372,56 +2549,37 @@ public: /*.legacyRegisterOp=*/ nullptr }; }; -#undef QT_METATYPE_CONSTEXPRLAMDA /* MSVC instantiates extern templates (https://developercommunity.visualstudio.com/t/c11-extern-templates-doesnt-work-for-class-templat/157868) + + The INTEGRITY compiler apparently does too. + + On Windows (with other compilers or whenever MSVC is fixed), we can't declare + QMetaTypeInterfaceWrapper with __declspec(dllimport) because taking its + address is not a core constant expression. */ -#if !defined(QT_BOOTSTRAPPED) && !defined(Q_CC_MSVC) +#if !defined(QT_BOOTSTRAPPED) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY) -#if !defined(QT_BUILD_CORE_LIB) -#define QT_METATYPE_TEMPLATE_EXPORT Q_CORE_EXPORT +#ifdef QT_NO_DATA_RELOCATION +# define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \ + extern template class Q_CORE_EXPORT QMetaTypeForType<Name>; #else -#define QT_METATYPE_TEMPLATE_EXPORT +# define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \ + extern template class Q_CORE_EXPORT QMetaTypeForType<Name>; \ + extern template struct Q_CORE_EXPORT QMetaTypeInterfaceWrapper<Name>; #endif -#define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \ - extern template class QT_METATYPE_TEMPLATE_EXPORT QMetaTypeForType<Name>; -QT_WARNING_PUSH -QT_WARNING_DISABLE_GCC("-Wattributes") // false positive because of QMetaTypeForType<void> -QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) -QT_WARNING_POP +QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER) #undef QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER -#undef QT_METATYPE_TEMPLATE_EXPORT #endif template<typename T> -constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType() -{ - using Ty = std::remove_cv_t<std::remove_reference_t<T>>; - return &QMetaTypeInterfaceWrapper<Ty>::metaType; -} - -namespace detail { -template<typename T, typename ODR_VIOLATION_PREVENTER> -struct is_complete_helper -{ - template<typename U> - static auto check(U *) -> std::integral_constant<bool, sizeof(U) != 0>; - static auto check(...) -> std::false_type; - using type = decltype(check(static_cast<T *>(nullptr))); -}; -} // namespace detail - -template <typename T, typename ODR_VIOLATION_PREVENTER> -struct is_complete : detail::is_complete_helper<T, ODR_VIOLATION_PREVENTER>::type {}; - -template<typename T> struct qRemovePointerLike { using type = std::remove_pointer_t<T>; @@ -2446,16 +2604,34 @@ struct TypeAndForceComplete using ForceComplete = ForceComplete_; }; +template<typename T> +constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType() +{ + // don't check the type is suitable here + using Ty = typename MetatypeDecay<T>::type; + return &QMetaTypeInterfaceWrapper<Ty>::metaType; +} + template<typename Unique, typename TypeCompletePair> constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType() { using T = typename TypeCompletePair::type; using ForceComplete = typename TypeCompletePair::ForceComplete; - using Ty = std::remove_cv_t<std::remove_reference_t<T>>; + using Ty = typename MetatypeDecay<T>::type; using Tz = qRemovePointerLike_t<Ty>; - if constexpr (!is_complete<Tz, Unique>::value && !ForceComplete::value) { + + if constexpr (std::is_void_v<Tz>) { + // early out to avoid expanding the rest of the templates + return &QMetaTypeInterfaceWrapper<Ty>::metaType; + } else if constexpr (ForceComplete::value) { + checkTypeIsSuitableForMetaType<Ty>(); + return &QMetaTypeInterfaceWrapper<Ty>::metaType; + } else if constexpr (std::is_reference_v<Tz>) { + return nullptr; + } else if constexpr (!is_complete<Tz, Unique>::value) { return nullptr; } else { + // don't check the type is suitable here return &QMetaTypeInterfaceWrapper<Ty>::metaType; } } @@ -2465,6 +2641,7 @@ constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType() template<typename T> constexpr QMetaType QMetaType::fromType() { + QtPrivate::checkTypeIsSuitableForMetaType<T>(); return QMetaType(QtPrivate::qMetaTypeInterfaceForType<T>()); } @@ -2490,7 +2667,14 @@ constexpr const QMetaObject *QMetaType::metaObject() const template<typename... T> constexpr const QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = { - QtPrivate::qMetaTypeInterfaceForType<T>()... + /* + Unique in qTryMetaTypeInterfaceForType does not have to be unique here + as we require _all_ types here to be actually complete. + We just want to have the additional type processing that exist in + QtPrivate::qTryMetaTypeInterfaceForType as opposed to the normal + QtPrivate::qMetaTypeInterfaceForType used in QMetaType::fromType + */ + QtPrivate::qTryMetaTypeInterfaceForType<void, QtPrivate::TypeAndForceComplete<T, std::true_type>>()... }; constexpr const char *QMetaType::name() const @@ -2503,8 +2687,16 @@ constexpr const QtPrivate::QMetaTypeInterface *const qt_incomplete_metaTypeArray QtPrivate::qTryMetaTypeInterfaceForType<Unique, T>()... }; +inline size_t qHash(QMetaType type, size_t seed = 0) +{ + // We cannot use d_ptr here since the same type in different DLLs + // might result in different pointers! + return qHash(type.id(), seed); +} + QT_END_NAMESPACE -Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl) +QT_DECL_METATYPE_EXTERN_TAGGED(QtMetaTypePrivate::QPairVariantInterfaceImpl, + QPairVariantInterfaceImpl, Q_CORE_EXPORT) #endif // QMETATYPE_H |