QMetaType: add registerType() and qRegisterMetaType(QMetaType)
This also rewrites QMetaType::id() on top of the helper, with the benefit of calling a member static function, so QMetaType doesn't need to be spilled onto the stack. In some upcoming changes I need to ensure that QMetaTypes are registered so they can be found by name and I'd like to have a dedicated function name for that, instead of calling .id(). Since I needed to add docs for the new function, I've updated for the old one too. [ChangeLog][QMetaType] Added QMetaType::registerType() and an overload of qRegisterMetaType() taking QMetaType (the two functions do the same thing). These two functions ensure a given QMetaType is registered with the Qt global registry, so they can be found by name later. Using qRegisterMetaType<T>() also accomplishes the same thing, but is slightly better for completely generic code because it will avoid emitting the registration for built-in types. Change-Id: I3859764fed084846bcb0fffd170351d606034c22 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
b1d9331c15
commit
74fac865cf
@ -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)
|
||||
|
@ -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<T>()} must be called before the first connection
|
||||
is established.
|
||||
To use the type \c T in queued signal and slot connections,
|
||||
\c{qRegisterMetaType<T>()} 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<T>()} 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<T>()} 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
|
||||
|
@ -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 <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();
|
||||
@ -1298,6 +1317,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>
|
||||
|
@ -1424,20 +1424,27 @@ void tst_QMetaType::typedefs()
|
||||
QCOMPARE(QMetaType::type("WhityDouble"), ::qMetaTypeId<WhityDouble>());
|
||||
}
|
||||
|
||||
struct RegisterTypeType {};
|
||||
|
||||
void tst_QMetaType::registerType()
|
||||
{
|
||||
// Built-in
|
||||
QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
|
||||
QCOMPARE(qRegisterMetaType<QString>("QString"), int(QMetaType::QString));
|
||||
qRegisterMetaType(QMetaType::fromType<QString>());
|
||||
|
||||
// Custom
|
||||
int fooId = qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo");
|
||||
QVERIFY(fooId >= int(QMetaType::User));
|
||||
QCOMPARE(qRegisterMetaType<TestSpace::Foo>("TestSpace::Foo"), fooId);
|
||||
qRegisterMetaType(QMetaType::fromType<TestSpace::Foo>());
|
||||
|
||||
int movableId = qRegisterMetaType<CustomMovable>("CustomMovable");
|
||||
QVERIFY(movableId >= int(QMetaType::User));
|
||||
QCOMPARE(qRegisterMetaType<CustomMovable>("CustomMovable"), movableId);
|
||||
qRegisterMetaType(QMetaType::fromType<CustomMovable>());
|
||||
|
||||
// Aliases are deprecated
|
||||
|
||||
// Alias to built-in
|
||||
typedef QString MyString;
|
||||
@ -1460,6 +1467,23 @@ void tst_QMetaType::registerType()
|
||||
QCOMPARE(qRegisterMetaType<MyFoo>("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<RegisterTypeType>();
|
||||
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 { };
|
||||
|
Loading…
x
Reference in New Issue
Block a user