diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2023-09-13 10:27:04 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2023-09-20 00:05:53 +0200 |
commit | 4a6cbfbe5c90158ab2f4afed3d188dae3ec0ea85 (patch) | |
tree | 01146af662d24b5f1e1b3543c6745c1e56f02cb4 | |
parent | 41824a02cbc63a15a2a487044a40b85a25bd0c99 (diff) |
QVariant: add fromMetaType
The QVariant(QMetaType) constructor is a major anti-pattern: unlike
*every* other QVariant's constructor, it doesn't build a QVariant
holding the QMetaType object, but a QVariant of the specified type.
Introduce a named constructor for this use case instead.
In principle, this should lead to a deprecation of the QMetaType
constructor... except that it's used everywhere, so I can't do it at
this time.
Drive-by, improve the documentation of the QVariant(QMetaType)
constructor (since it's basically c&p for the new fromMetaType
function).
[ChangeLog][QtCore][QVariant] Added the QVariant::fromMetaType named
constructor, that builds a QVariant of a given QMetaType.
Change-Id: I4a499526bd0fe98eed0c1a3e91bcfc21efa9e352
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 61 | ||||
-rw-r--r-- | src/corelib/kernel/qvariant.h | 4 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 18 |
3 files changed, 69 insertions, 14 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 2c8e61fa34..f8a3747207 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -516,7 +516,7 @@ void QVariant::create(int type, const void *copy) */ void QVariant::create(QMetaType type, const void *copy) { - *this = QVariant(type, copy); + *this = QVariant::fromMetaType(type, copy); } /*! @@ -910,27 +910,27 @@ void *QVariant::prepareForEmplace(QMetaType type) */ /*! - Constructs variant of type \a type, and initializes with - \a copy if \a copy is not \nullptr. + Constructs a variant of type \a type, and initializes it with + a copy of \c{*copy} if \a copy is not \nullptr (in which case, \a copy + must point to an object of type \a type). - Note that you have to pass the address of the variable you want stored. + Note that you have to pass the address of the object you want stored. Usually, you never have to use this constructor, use QVariant::fromValue() instead to construct variants from the pointer types represented by \c QMetaType::VoidStar, and \c QMetaType::QObjectStar. - If \a type does not support copy and default construction, the variant will - be invalid. + If \a type does not support copy construction and \a copy is not \nullptr, + the variant will be invalid. Similarly, if \a copy is \nullptr and + \a type does not support default construction, the variant will be + invalid. - \sa QVariant::fromValue(), QMetaType::Type + \sa QVariant::fromMetaType, QVariant::fromValue(), QMetaType::Type */ -QVariant::QVariant(QMetaType type, const void *copy) : d(type.iface()) +QVariant::QVariant(QMetaType type, const void *copy) + : d() { - type.registerType(); - if (isValidMetaTypeForVariant(type.iface(), copy)) - customConstruct(type.iface(), &d, copy); - else - d = {}; + *this = fromMetaType(type, copy); } QVariant::QVariant(int val) noexcept : d(std::piecewise_construct_t{}, val) {} @@ -2711,6 +2711,41 @@ QT_WARNING_POP \overload */ + +/*! + \since 6.7 + + Creates a variant of type \a type, and initializes it with + a copy of \c{*copy} if \a copy is not \nullptr (in which case, \a copy + must point to an object of type \a type). + + Note that you have to pass the address of the object you want stored. + + Usually, you never have to use this constructor, use QVariant::fromValue() + instead to construct variants from the pointer types represented by + \c QMetaType::VoidStar, and \c QMetaType::QObjectStar. + + If \a type does not support copy construction and \a copy is not \nullptr, + the variant will be invalid. Similarly, if \a copy is \nullptr and + \a type does not support default construction, the variant will be + invalid. + + Returns the QVariant created as described above. + + \sa QVariant::fromValue(), QMetaType::Type +*/ +QVariant QVariant::fromMetaType(QMetaType type, const void *copy) +{ + QVariant result; + type.registerType(); + const auto iface = type.iface(); + if (isValidMetaTypeForVariant(iface, copy)) { + result.d = Private(iface); + customConstruct(iface, &result.d, copy); + } + return result; +} + /*! \fn template<typename T> T qvariant_cast(const QVariant &value) \relates QVariant diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 2c8df591e2..c57eed97fb 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -539,7 +539,7 @@ public: // handle special cases using Type = std::remove_cv_t<T>; if constexpr (std::is_null_pointer_v<Type>) - return QVariant(QMetaType::fromType<std::nullptr_t>()); + return QVariant::fromMetaType(QMetaType::fromType<std::nullptr_t>()); else if constexpr (std::is_same_v<Type, QVariant>) return std::forward<T>(value); else if constexpr (std::is_same_v<Type, std::monostate>) @@ -586,6 +586,8 @@ public: return fromStdVariantImpl(std::move(value)); } + static QVariant fromMetaType(QMetaType type, const void *copy = nullptr); + template<typename T> bool canConvert() const { return canConvert(QMetaType::fromType<T>()); } diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 3a621b91d6..a1f9531093 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -442,11 +442,21 @@ void tst_QVariant::constructor() QVERIFY(var3.isNull()); QVERIFY(var3.isValid()); + QVariant var3a = QVariant::fromMetaType(QMetaType::fromType<QString>()); + QCOMPARE(var3a.typeName(), "QString"); + QVERIFY(var3a.isNull()); + QVERIFY(var3a.isValid()); + QVariant var4 {QMetaType()}; QCOMPARE(var4.typeId(), QMetaType::UnknownType); QVERIFY(var4.isNull()); QVERIFY(!var4.isValid()); + QVariant var4a = QVariant::fromMetaType(QMetaType()); + QCOMPARE(var4a.typeId(), QMetaType::UnknownType); + QVERIFY(var4a.isNull()); + QVERIFY(!var4a.isValid()); + QVariant var5(QLatin1String("hallo")); QCOMPARE(var5.typeId(), QMetaType::QString); QCOMPARE(var5.typeName(), "QString"); @@ -489,6 +499,14 @@ void tst_QVariant::constructor_invalid() } { QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type")); + QVariant variant = QVariant::fromMetaType(QMetaType(typeId)); + QVERIFY(!variant.isValid()); + QVERIFY(variant.isNull()); + QCOMPARE(variant.typeId(), int(QMetaType::UnknownType)); + QCOMPARE(variant.userType(), int(QMetaType::UnknownType)); + } + { + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type")); QVariant variant(QMetaType(typeId), /* copy */ nullptr); QVERIFY(!variant.isValid()); QVERIFY(variant.isNull()); |