diff options
Diffstat (limited to 'src/corelib/kernel/qvariant.cpp')
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 407 |
1 files changed, 288 insertions, 119 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 75bdef2383..92a44c462b 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -3,7 +3,7 @@ // Copyright (C) 2015 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 -#include "qvariant.h" +#include "qvariant_p.h" #include "qbitarray.h" #include "qbytearray.h" #include "qdatastream.h" @@ -47,6 +47,8 @@ #include "qline.h" #endif +#include <memory> + #include <cmath> #include <float.h> #include <cstring> @@ -125,7 +127,7 @@ static std::optional<qlonglong> qConvertToNumber(const QVariant::Private *d, boo if (s == "true"_L1 || s == "1"_L1) return 1; } - return 0; + return std::nullopt; } case QMetaType::QChar: return d->get<QChar>().unicode(); @@ -171,20 +173,20 @@ static std::optional<qlonglong> qConvertToNumber(const QVariant::Private *d, boo return std::nullopt; } -static std::optional<qreal> qConvertToRealNumber(const QVariant::Private *d) +static std::optional<double> qConvertToRealNumber(const QVariant::Private *d) { bool ok; switch (d->typeInterface()->typeId) { case QMetaType::QString: if (double r = d->get<QString>().toDouble(&ok); ok) - return qreal(r); + return r; return std::nullopt; case QMetaType::Double: - return qreal(d->get<double>()); + return d->get<double>(); case QMetaType::Float: - return qreal(d->get<float>()); + return double(d->get<float>()); case QMetaType::Float16: - return qreal(d->get<qfloat16>()); + return double(d->get<qfloat16>()); case QMetaType::ULongLong: case QMetaType::UInt: case QMetaType::UChar: @@ -192,7 +194,7 @@ static std::optional<qreal> qConvertToRealNumber(const QVariant::Private *d) case QMetaType::Char32: case QMetaType::UShort: case QMetaType::ULong: - return qreal(qMetaTypeUNumber(d)); + return double(qMetaTypeUNumber(d)); #ifndef QT_BOOTSTRAPPED case QMetaType::QCborValue: return d->get<QCborValue>().toDouble(); @@ -202,7 +204,7 @@ static std::optional<qreal> qConvertToRealNumber(const QVariant::Private *d) default: // includes enum conversion as well as invalid types if (std::optional<qlonglong> l = qConvertToNumber(d)) - return qreal(*l); + return double(*l); return std::nullopt; } } @@ -231,24 +233,22 @@ static bool isValidMetaTypeForVariant(const QtPrivate::QMetaTypeInterface *iface return true; } -template <typename F> static QVariant::PrivateShared * -customConstructShared(size_t size, size_t align, F &&construct) -{ - struct Deleter { - void operator()(QVariant::PrivateShared *p) const - { QVariant::PrivateShared::free(p); } - }; +enum CustomConstructMoveOptions { + UseCopy, // custom construct uses the copy ctor unconditionally + // future option: TryMove: uses move ctor if available, else copy ctor + ForceMove, // custom construct use the move ctor (which must exist) +}; - // this is exception-safe - std::unique_ptr<QVariant::PrivateShared, Deleter> ptr; - ptr.reset(QVariant::PrivateShared::create(size, align)); - construct(ptr->data()); - return ptr.release(); -} +enum CustomConstructNullabilityOption { + MaybeNull, // copy might be null, might be non-null + NonNull, // copy is guarantueed to be non-null + // future option: AlwaysNull? +}; // the type of d has already been set, but other field are not set +template <CustomConstructMoveOptions moveOption = UseCopy, CustomConstructNullabilityOption nullability = MaybeNull> static void customConstruct(const QtPrivate::QMetaTypeInterface *iface, QVariant::Private *d, - const void *copy) + std::conditional_t<moveOption == ForceMove, void *, const void *> copy) { using namespace QtMetaTypePrivate; Q_ASSERT(iface); @@ -257,6 +257,10 @@ static void customConstruct(const QtPrivate::QMetaTypeInterface *iface, QVariant Q_ASSERT(isCopyConstructible(iface)); Q_ASSERT(isDestructible(iface)); Q_ASSERT(copy || isDefaultConstructible(iface)); + if constexpr (moveOption == ForceMove) + Q_ASSERT(isMoveConstructible(iface)); + if constexpr (nullability == NonNull) + Q_ASSERT(copy != nullptr); // need to check for nullptr_t here, as this can get called by fromValue(nullptr). fromValue() uses // std::addressof(value) which in this case returns the address of the nullptr object. @@ -266,11 +270,17 @@ static void customConstruct(const QtPrivate::QMetaTypeInterface *iface, QVariant if (QVariant::Private::canUseInternalSpace(iface)) { d->is_shared = false; if (!copy && !iface->defaultCtr) - return; // trivial default constructor, we've already memset - construct(iface, d->data.data, copy); + return; // trivial default constructor and it's OK to build in 0-filled storage, which we've already done + if constexpr (moveOption == ForceMove && nullability == NonNull) + moveConstruct(iface, d->data.data, copy); + else + construct(iface, d->data.data, copy); } else { d->data.shared = customConstructShared(iface->size, iface->alignment, [=](void *where) { - construct(iface, where, copy); + if constexpr (moveOption == ForceMove && nullability == NonNull) + moveConstruct(iface, where, copy); + else + construct(iface, where, copy); }); d->is_shared = true; } @@ -306,59 +316,6 @@ static QVariant::Private clonePrivate(const QVariant::Private &other) } // anonymous used to hide QVariant handlers -inline QVariant::PrivateShared *QVariant::PrivateShared::create(size_t size, size_t align) -{ - size += sizeof(PrivateShared); - if (align > sizeof(PrivateShared)) { - // The alignment is larger than the alignment we can guarantee for the pointer - // directly following PrivateShared, so we need to allocate some additional - // memory to be able to fit the object into the available memory with suitable - // alignment. - size += align - sizeof(PrivateShared); - } - void *data = operator new(size); - auto *ps = new (data) QVariant::PrivateShared(); - ps->offset = int(((quintptr(ps) + sizeof(PrivateShared) + align - 1) & ~(align - 1)) - quintptr(ps)); - return ps; -} - -inline void QVariant::PrivateShared::free(PrivateShared *p) -{ - p->~PrivateShared(); - operator delete(p); -} - -inline QVariant::Private::Private(const QtPrivate::QMetaTypeInterface *iface) noexcept - : is_shared(false), is_null(false), packedType(quintptr(iface) >> 2) -{ - Q_ASSERT((quintptr(iface) & 0x3) == 0); -} - -template <typename T> inline -QVariant::Private::Private(std::piecewise_construct_t, const T &t) - : is_shared(!CanUseInternalSpace<T>), is_null(std::is_same_v<T, std::nullptr_t>) -{ - // confirm noexceptness - static constexpr bool isNothrowQVariantConstructible = noexcept(QVariant(t)); - static constexpr bool isNothrowCopyConstructible = std::is_nothrow_copy_constructible_v<T>; - static constexpr bool isNothrowCopyAssignable = std::is_nothrow_copy_assignable_v<T>; - - const QtPrivate::QMetaTypeInterface *iface = QtPrivate::qMetaTypeInterfaceForType<T>(); - Q_ASSERT((quintptr(iface) & 0x3) == 0); - packedType = quintptr(iface) >> 2; - - if constexpr (CanUseInternalSpace<T>) { - static_assert(isNothrowQVariantConstructible == isNothrowCopyConstructible); - static_assert(isNothrowQVariantConstructible == isNothrowCopyAssignable); - new (data.data) T(t); - } else { - static_assert(!isNothrowQVariantConstructible); // we allocate memory, even if T doesn't - data.shared = customConstructShared(sizeof(T), alignof(T), [=](void *where) { - new (where) T(t); - }); - } -} - /*! \class QVariant \inmodule QtCore @@ -367,6 +324,7 @@ QVariant::Private::Private(std::piecewise_construct_t, const T &t) \ingroup objectmodel \ingroup shared + \compares equality Because C++ forbids unions from including types that have non-default constructors or destructors, most interesting Qt @@ -559,23 +517,18 @@ 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); } /*! \fn QVariant::~QVariant() Destroys the QVariant and the contained object. - - Note that subclasses that reimplement clear() should reimplement - the destructor to call clear(). This destructor calls clear(), but - because it is the destructor, QVariant::clear() is called rather - than a subclass's clear(). */ QVariant::~QVariant() { - if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared)) + if (!d.is_shared || !d.data.shared->ref.deref()) customClear(&d); } @@ -592,6 +545,106 @@ QVariant::QVariant(const QVariant &p) } /*! + \fn template <typename T, typename... Args, QVariant::if_constructible<T, Args...> = true> QVariant::QVariant(std::in_place_type_t<T>, Args&&... args) noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, Args...>::value) + + \since 6.6 + Constructs a new variant containing a value of type \c T. The contained + value is is initialized with the arguments + \c{std::forward<Args>(args)...}. + + This overload only participates in overload resolution if \c T can be + constructed from \a args. + + This constructor is provided for STL/std::any compatibility. + + \overload + */ + +/*! + + \fn template <typename T, typename U, typename... Args, QVariant::if_constructible<T, std::initializer_list<U> &, Args...> = true> explicit QVariant::QVariant(std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args) noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, std::initializer_list<U> &, Args... >::value) + + \since 6.6 + \overload + This overload exists to support types with constructors taking an + \c initializer_list. It behaves otherwise equivalent to the + non-initializer list \c{in_place_type_t} overload. +*/ + + +/*! + \fn template <typename T, typename... Args, QVariant::if_constructible<T, Args...> = true> QVariant::emplace(Args&&... args) + + \since 6.6 + Replaces the object currently held in \c{*this} with an object of + type \c{T}, constructed from \a{args}\c{...}. If \c{*this} was non-null, + the previously held object is destroyed first. + If possible, this method will reuse memory allocated by the QVariant. + Returns a reference to the newly-created object. + */ + +/*! + \fn template <typename T, typename U, typename... Args, QVariant::if_constructible<T, std::initializer_list<U> &, Args...> = true> QVariant::emplace(std::initializer_list<U> list, Args&&... args) + + \since 6.6 + \overload + This overload exists to support types with constructors taking an + \c initializer_list. It behaves otherwise equivalent to the + non-initializer list overload. +*/ + +QVariant::QVariant(std::in_place_t, QMetaType type) : d(type.iface()) +{ + // we query the metatype instead of detecting it at compile time + // so that we can change relocatability of internal types + if (!Private::canUseInternalSpace(type.iface())) { + d.data.shared = PrivateShared::create(type.sizeOf(), type.alignOf()); + d.is_shared = true; + } +} + +/*! + \internal + Returns a pointer to data suitable for placement new + of an object of type \a type + Changes the variant's metatype to \a type + */ +void *QVariant::prepareForEmplace(QMetaType type) +{ + /* There are two cases where we can reuse the existing storage + (1) The new type fits in QVariant's SBO storage + (2) We are using the externally allocated storage, the variant is + detached, and the new type fits into the existing storage. + In all other cases (3), we cannot reuse the storage. + */ + auto typeFits = [&] { + auto newIface = type.iface(); + auto oldIface = d.typeInterface(); + auto newSize = PrivateShared::computeAllocationSize(newIface->size, newIface->alignment); + auto oldSize = PrivateShared::computeAllocationSize(oldIface->size, oldIface->alignment); + return newSize <= oldSize; + }; + if (Private::canUseInternalSpace(type.iface())) { // (1) + clear(); + d.packedType = quintptr(type.iface()) >> 2; + return d.data.data; + } else if (d.is_shared && isDetached() && typeFits()) { // (2) + QtMetaTypePrivate::destruct(d.typeInterface(), d.data.shared->data()); + // compare QVariant::PrivateShared::create + const auto ps = d.data.shared; + const auto align = type.alignOf(); + ps->offset = PrivateShared::computeOffset(ps, align); + d.packedType = quintptr(type.iface()) >> 2; + return ps->data(); + } + // (3) + QVariant newVariant(std::in_place, type); + swap(newVariant); + // const cast is safe, we're in a non-const method + return const_cast<void *>(d.storage()); +} + +/*! \fn QVariant::QVariant(const QString &val) noexcept Constructs a new variant with a string value, \a val. @@ -600,7 +653,8 @@ QVariant::QVariant(const QVariant &p) /*! \fn QVariant::QVariant(QLatin1StringView val) - Constructs a new variant with a string value, \a val. + Constructs a new variant with a QString value from the Latin-1 + string viewed by \a val. */ /*! @@ -857,26 +911,27 @@ QVariant::QVariant(const QVariant &p) */ /*! - 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() { - 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) {} @@ -888,7 +943,9 @@ QVariant::QVariant(double val) noexcept : d(std::piecewise_construct_t{}, val) { QVariant::QVariant(float val) noexcept : d(std::piecewise_construct_t{}, val) {} QVariant::QVariant(const QByteArray &val) noexcept : d(std::piecewise_construct_t{}, val) {} +#ifndef QT_BOOTSTRAPPED QVariant::QVariant(const QBitArray &val) noexcept : d(std::piecewise_construct_t{}, val) {} +#endif QVariant::QVariant(const QString &val) noexcept : d(std::piecewise_construct_t{}, val) {} QVariant::QVariant(QChar val) noexcept : d(std::piecewise_construct_t{}, val) {} QVariant::QVariant(const QStringList &val) noexcept : d(std::piecewise_construct_t{}, val) {} @@ -1035,7 +1092,8 @@ void QVariant::detach() Q_ASSERT(isValidMetaTypeForVariant(d.typeInterface(), constData())); Private dd(d.typeInterface()); - customConstruct(d.typeInterface(), &dd, constData()); + // null variant is never shared; anything else is NonNull + customConstruct<UseCopy, NonNull>(d.typeInterface(), &dd, constData()); if (!d.data.shared->ref.deref()) customClear(&d); d.data.shared = dd.data.shared; @@ -1064,7 +1122,7 @@ const char *QVariant::typeName() const */ void QVariant::clear() { - if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared)) + if (!d.is_shared || !d.data.shared->ref.deref()) customClear(&d); d = {}; } @@ -1360,12 +1418,14 @@ QDataStream &operator<<(QDataStream &s, const QVariant &p) } /*! \fn QDataStream& operator>>(QDataStream &s, QVariant::Type &p) + \relates QVariant \deprecated [6.0] Stream QMetaType::Type instead. Reads a variant type \a p in enum representation from the stream \a s. */ /*! \fn QDataStream& operator<<(QDataStream &s, const QVariant::Type p) + \relates QVariant \deprecated [6.0] Stream QMetaType::Type instead. Writes a variant type \a p to the stream \a s. @@ -1786,6 +1846,7 @@ QChar QVariant::toChar() const return qvariant_cast<QChar>(*this); } +#ifndef QT_BOOTSTRAPPED /*! Returns the variant as a QBitArray if the variant has userType() \l QMetaType::QBitArray; otherwise returns an empty bit array. @@ -1796,6 +1857,7 @@ QBitArray QVariant::toBitArray() const { return qvariant_cast<QBitArray>(*this); } +#endif // QT_BOOTSTRAPPED template <typename T> inline T qNumVariantToHelper(const QVariant::Private &d, bool *ok) @@ -2091,9 +2153,9 @@ bool QVariant::view(int type, void *ptr) } /*! - \fn bool QVariant::operator==(const QVariant &v1, const QVariant &v2) + \fn bool QVariant::operator==(const QVariant &lhs, const QVariant &rhs) - Returns \c true if \a v1 and \a v2 are equal; otherwise returns \c false. + Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false. QVariant uses the equality operator of the type() contained to check for equality. @@ -2117,9 +2179,9 @@ bool QVariant::view(int type, void *ptr) */ /*! - \fn bool QVariant::operator!=(const QVariant &v1, const QVariant &v2) + \fn bool QVariant::operator!=(const QVariant &lhs, const QVariant &rhs) - Returns \c false if \a v1 and \a v2 are equal; otherwise returns \c true. + Returns \c false if \a lhs and \a rhs are equal; otherwise returns \c true. QVariant uses the equality operator of the type() contained to check for equality. @@ -2299,19 +2361,19 @@ static QPartialOrdering numericCompare(const QVariant::Private *d1, const QVaria if (promotedType != QMetaType::QReal) return integralCompare(promotedType, d1, d2); - // qreal comparisons - std::optional<qreal> r1 = qConvertToRealNumber(d1); - std::optional<qreal> r2 = qConvertToRealNumber(d2); + // floating point comparison + const auto r1 = qConvertToRealNumber(d1); + const auto r2 = qConvertToRealNumber(d2); if (!r1 || !r2) return QPartialOrdering::Unordered; if (*r1 == *r2) return QPartialOrdering::Equivalent; - return spaceShip<qreal>(*r1, *r2); + return spaceShip(*r1, *r2); } #ifndef QT_BOOTSTRAPPED -static bool canConvertMetaObject(QMetaType fromType, QMetaType toType) +static bool qvCanConvertMetaObject(QMetaType fromType, QMetaType toType) { if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) { @@ -2341,7 +2403,7 @@ bool QVariant::equals(const QVariant &v) const return numericCompare(&d, &v.d) == QPartialOrdering::Equivalent; #ifndef QT_BOOTSTRAPPED // if both types are related pointers to QObjects, check if they point to the same object - if (canConvertMetaObject(metatype, v.metaType())) + if (qvCanConvertMetaObject(metatype, v.metaType())) return pointerCompare(&d, &v.d) == QPartialOrdering::Equivalent; #endif return false; @@ -2384,7 +2446,7 @@ QPartialOrdering QVariant::compare(const QVariant &lhs, const QVariant &rhs) if (canBeNumericallyCompared(lhs.d.type().iface(), rhs.d.type().iface())) return numericCompare(&lhs.d, &rhs.d); #ifndef QT_BOOTSTRAPPED - if (canConvertMetaObject(lhs.metaType(), rhs.metaType())) + if (qvCanConvertMetaObject(lhs.metaType(), rhs.metaType())) return pointerCompare(&lhs.d, &rhs.d); #endif return QPartialOrdering::Unordered; @@ -2399,7 +2461,7 @@ QPartialOrdering QVariant::compare(const QVariant &lhs, const QVariant &rhs) Returns a pointer to the contained object as a generic void* that cannot be written to. - \sa QMetaType + \sa get_if(), QMetaType */ /*! @@ -2409,7 +2471,7 @@ QPartialOrdering QVariant::compare(const QVariant &lhs, const QVariant &rhs) This function detaches the QVariant. When called on a \l{isNull}{null-QVariant}, the QVariant will not be null after the call. - \sa QMetaType + \sa get_if(), QMetaType */ void *QVariant::data() { @@ -2420,6 +2482,42 @@ void *QVariant::data() } /*! + \since 6.6 + \fn template <typename T> const T* QVariant::get_if(const QVariant *v) + \fn template <typename T> T* QVariant::get_if(QVariant *v) + + If \a v contains an object of type \c T, returns a pointer to the contained + object, otherwise returns \nullptr. + + The overload taking a mutable \a v detaches \a v: When called on a + \l{isNull()}{null} \a v with matching type \c T, \a v will not be null + after the call. + + These functions are provided for compatibility with \c{std::variant}. + + \sa data() +*/ + +/*! + \since 6.6 + \fn template <typename T> T &QVariant::get(QVariant &v) + \fn template <typename T> const T &QVariant::get(const QVariant &v) + \fn template <typename T> T &&QVariant::get(QVariant &&v) + \fn template <typename T> const T &&QVariant::get(const QVariant &&v) + + If \a v contains an object of type \c T, returns a reference to the contained + object, otherwise the call has undefined behavior. + + The overloads taking a mutable \a v detach \a v: When called on a + \l{isNull()}{null} \a v with matching type \c T, \a v will not be null + after the call. + + These functions are provided for compatibility with \c{std::variant}. + + \sa get_if(), data() +*/ + +/*! Returns \c true if this is a null variant, false otherwise. A variant is considered null if it contains no initialized value or a null pointer. @@ -2457,6 +2555,22 @@ QDebug QVariant::qdebugHelper(QDebug dbg) const return dbg; } +QVariant QVariant::moveConstruct(QMetaType type, void *data) +{ + QVariant var; + var.d = QVariant::Private(type.d_ptr); + customConstruct<ForceMove, NonNull>(type.d_ptr, &var.d, data); + return var; +} + +QVariant QVariant::copyConstruct(QMetaType type, const void *data) +{ + QVariant var; + var.d = QVariant::Private(type.d_ptr); + customConstruct<UseCopy, NonNull>(type.d_ptr, &var.d, data); + return var; +} + #if QT_DEPRECATED_SINCE(6, 0) QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED @@ -2476,7 +2590,7 @@ QT_WARNING_POP #endif -/*! \fn template<typename T> void QVariant::setValue(T &&value) +/*! \fn template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>> void QVariant::setValue(T &&value) Stores a copy of \a value. If \c{T} is a type that QVariant doesn't support, QMetaType is used to store the value. A compile @@ -2489,19 +2603,19 @@ QT_WARNING_POP \sa value(), fromValue(), canConvert() */ -/*! \fn template<typename T> void QVariant::setValue(const QVariant &value) +/*! \fn void QVariant::setValue(const QVariant &value) Copies \a value over this QVariant. It is equivalent to simply assigning \a value to this QVariant. */ -/*! \fn template<typename T> void QVariant::setValue(QVariant &&value) +/*! \fn void QVariant::setValue(QVariant &&value) Moves \a value over this QVariant. It is equivalent to simply move assigning \a value to this QVariant. */ -/*! \fn template<typename T> T QVariant::value() const +/*! \fn template<typename T> T QVariant::value() const & Returns the stored value converted to the template type \c{T}. Call canConvert() to find out whether a type can be converted. @@ -2541,7 +2655,7 @@ QT_WARNING_POP \sa canView(), Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE() */ -/*! \fn bool QVariant::canConvert() const +/*! \fn template<typename T> bool QVariant::canConvert() const Returns \c true if the variant can be converted to the template type \c{T}, otherwise false. @@ -2557,7 +2671,7 @@ QT_WARNING_POP \sa convert() */ -/*! \fn bool QVariant::canView() const +/*! \fn template<typename T> bool QVariant::canView() const Returns \c true if a mutable view of the template type \c{T} can be created on this variant, otherwise \c false. @@ -2577,6 +2691,12 @@ QT_WARNING_POP \sa setValue(), value() */ +/*! \fn template<typename T, QVariant::if_rvalue<T> = true> static QVariant QVariant::fromValue(T &&value) + + \since 6.6 + \overload +*/ + /*! \fn template<typename... Types> QVariant QVariant::fromStdVariant(const std::variant<Types...> &value) \since 5.11 @@ -2591,6 +2711,47 @@ QT_WARNING_POP */ /*! + \fn template<typename... Types> QVariant QVariant::fromStdVariant(std::variant<Types...> &&value) + \since 6.6 + \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 @@ -2601,6 +2762,14 @@ QT_WARNING_POP \sa QVariant::value() */ +/*! + \fn template<typename T> T QVariant::qvariant_cast(QVariant &&value) + \overload + \since 6.7 + + Returns the given \a value converted to the template type \c{T}. +*/ + /*! \fn template<typename T> T qVariantValue(const QVariant &value) \relates QVariant \deprecated |