diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp index c4fe85f84fd..7ffefa027ef 100644 --- a/src/corelib/compat/removed_api.cpp +++ b/src/corelib/compat/removed_api.cpp @@ -283,6 +283,14 @@ QT_WARNING_POP #if QT_CORE_REMOVED_SINCE(6, 5) +#include "qmetatype.h" + +int QMetaType::idHelper() const +{ + Q_ASSERT(d_ptr); + return registerHelper(d_ptr); +} + #include "qxmlstream.h" QXmlStreamReader::QXmlStreamReader(const QByteArray &data) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 4aed2edebb8..ea7cd4a0c9b 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -495,19 +495,28 @@ bool QMetaType::isRegistered() const \fn int QMetaType::id() const \since 5.13 - Returns id type hold by this QMetatype instance. + Returns id type held by this QMetatype instance. */ +/*! + \fn void QMetaType::registerType() const + \since 6.5 + + Registers this QMetaType with the type registry so it can be found by name, + using QMetaType::fromName(). + + \sa qRegisterMetaType() + */ /*! \internal - The slowpath of id(). Precondition: d_ptr != nullptr -*/ -int QMetaType::idHelper() const + Out-of-line path for registerType() and slow path id(). + */ +int QMetaType::registerHelper(const QtPrivate::QMetaTypeInterface *iface) { - Q_ASSERT(d_ptr); + Q_ASSERT(iface); auto reg = customTypeRegistry(); if (reg) { - return reg->registerCustomType(d_ptr); + return reg->registerCustomType(iface); } return 0; } @@ -2890,6 +2899,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) /*! \fn int qRegisterMetaType(const char *typeName) \relates QMetaType + \obsolete \threadsafe Registers the type name \a typeName for the type \c{T}. Returns @@ -2926,8 +2936,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) \threadsafe \since 4.2 - Call this function to register the type \c T. \c T must be declared with - Q_DECLARE_METATYPE(). Returns the meta type Id. + Call this function to register the type \c T. Returns the meta type Id. Example: @@ -2938,22 +2947,45 @@ QMetaType QMetaType::fromName(QByteArrayView typeName) pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able to register pointers to forward declared types. - After a type has been registered, you can create and destroy - objects of that type dynamically at run-time. + To use the type \c T in QMetaType, QVariant, or with the + QObject::property() API, registration is not necessary. - To use the type \c T in QVariant, using Q_DECLARE_METATYPE() is - sufficient. To use the type \c T in queued signal and slot connections, - \c{qRegisterMetaType()} must be called before the first connection - is established. + To use the type \c T in queued signal and slot connections, + \c{qRegisterMetaType()} must be called before the first connection is + established. That is typically done in the constructor of the class that + uses \c T, or in the \c{main()} function. - Also, to use type \c T with the QObject::property() API, - \c{qRegisterMetaType()} must be called before it is used, typically - in the constructor of the class that uses \c T, or in the \c{main()} - function. + After a type has been registered, it can be found by its name using + QMetaType::fromName(). \sa Q_DECLARE_METATYPE() */ +/*! + \fn int qRegisterMetaType(QMetaType meta) + \relates QMetaType + \threadsafe + \since 6.5 + + Registers the meta type \a meta and returns its type Id. + + This function requires that \c{T} is a fully defined type at the point + where the function is called. For pointer types, it also requires that the + pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able + to register pointers to forward declared types. + + To use the type \c T in QMetaType, QVariant, or with the + QObject::property() API, registration is not necessary. + + To use the type \c T in queued signal and slot connections, + \c{qRegisterMetaType()} must be called before the first connection is + established. That is typically done in the constructor of the class that + uses \c T, or in the \c{main()} function. + + After a type has been registered, it can be found by its name using + QMetaType::fromName(). + */ + /*! \fn int qMetaTypeId() \relates QMetaType diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index f4d3c5b54d7..e9599af5bbc 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -426,6 +426,11 @@ public: bool isValid() const; bool isRegistered() const; + void registerType() const + { + // "register" is a reserved keyword + registerHelper(); + } #if QT_CORE_REMOVED_SINCE(6, 1) || defined(Q_QDOC) int id() const; #else @@ -434,12 +439,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; @@ -722,7 +722,23 @@ public: const QtPrivate::QMetaTypeInterface *iface() const { return d_ptr; } private: +#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; }; @@ -1285,6 +1301,9 @@ template inline constexpr int qMetaTypeId() { if constexpr (bool(QMetaTypeId2::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::MetaType; } else { return QMetaType::fromType().id(); @@ -1298,6 +1317,11 @@ inline constexpr int qRegisterMetaType() return id; } +inline int qRegisterMetaType(QMetaType meta) +{ + return meta.registerHelper(); +} + #ifndef QT_NO_QOBJECT template struct QMetaTypeIdQObject diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 9a3ab830cb8..c25c5c6b16f 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -1424,20 +1424,27 @@ void tst_QMetaType::typedefs() QCOMPARE(QMetaType::type("WhityDouble"), ::qMetaTypeId()); } +struct RegisterTypeType {}; + void tst_QMetaType::registerType() { // Built-in QCOMPARE(qRegisterMetaType("QString"), int(QMetaType::QString)); QCOMPARE(qRegisterMetaType("QString"), int(QMetaType::QString)); + qRegisterMetaType(QMetaType::fromType()); // Custom int fooId = qRegisterMetaType("TestSpace::Foo"); QVERIFY(fooId >= int(QMetaType::User)); QCOMPARE(qRegisterMetaType("TestSpace::Foo"), fooId); + qRegisterMetaType(QMetaType::fromType()); int movableId = qRegisterMetaType("CustomMovable"); QVERIFY(movableId >= int(QMetaType::User)); QCOMPARE(qRegisterMetaType("CustomMovable"), movableId); + qRegisterMetaType(QMetaType::fromType()); + + // Aliases are deprecated // Alias to built-in typedef QString MyString; @@ -1460,6 +1467,23 @@ void tst_QMetaType::registerType() QCOMPARE(qRegisterMetaType("MyFoo"), fooId); QCOMPARE(QMetaType::type("MyFoo"), fooId); + + // this portion of the test can only be run once + static bool typeWasRegistered = false; + if (!typeWasRegistered) { + QMetaType mt = QMetaType::fromType(); + QVERIFY(mt.isValid()); + QCOMPARE_NE(mt.name(), nullptr); + + QVERIFY(!mt.isRegistered()); + QVERIFY(!QMetaType::fromName(mt.name()).isValid()); + + QCOMPARE_GT(qRegisterMetaType(mt), 0); + typeWasRegistered = true; + + QVERIFY(mt.isRegistered()); + QVERIFY(QMetaType::fromName(mt.name()).isValid()); + } } class IsRegisteredDummyType { };