diff options
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 19 | ||||
-rw-r--r-- | src/corelib/kernel/qvariant.h | 22 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 89 |
3 files changed, 128 insertions, 2 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 704b46e1c1..d799487d3c 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2371,6 +2371,25 @@ void *QVariant::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. diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 50b7e8c2bd..50ede63987 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -10,9 +10,12 @@ #ifndef QT_NO_DEBUG_STREAM #include <QtCore/qdebug.h> #endif + #include <memory> -#include <type_traits> +#include <QtCore/q20type_traits.h> +#include <QtCore/q23utility.h> #include <variant> + #if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1 # include <QtCore/qlist.h> # include <QtCore/qstringlist.h> @@ -25,6 +28,7 @@ QT_BEGIN_NAMESPACE QT_ENABLE_P0846_SEMANTICS_FOR(get_if) +QT_ENABLE_P0846_SEMANTICS_FOR(get) class QBitArray; class QDataStream; @@ -494,6 +498,22 @@ private: return static_cast<const T*>(v->data()); } +#define Q_MK_GET(cvref) \ + template <typename T> \ + friend T cvref get(QVariant cvref v) \ + { \ + if constexpr (std::is_const_v<T cvref>) \ + Q_ASSERT(!v.d.is_null); \ + Q_ASSERT(v.d.type() == QMetaType::fromType<q20::remove_cvref_t<T>>()); \ + return static_cast<T cvref>(*get_if<T>(&v)); \ + } \ + /* end */ + Q_MK_GET(&) + Q_MK_GET(const &) + Q_MK_GET(&&) + Q_MK_GET(const &&) +#undef Q_MK_GET + template<typename T> friend inline T qvariant_cast(const QVariant &); protected: diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index e5ffe14c97..cbe3f90b94 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -17,9 +17,17 @@ constexpr inline bool my_is_same_v<T, T> = true; #define CHECK_GET_IF(Variant, cvref) \ CHECK_IMPL(get_if, int, Variant, cvref *, int) +#define CHECK_GET(Variant, cvref) \ + CHECK_IMPL(get, int, Variant, cvref, int) + CHECK_GET_IF(QVariant, /* unadorned */); CHECK_GET_IF(QVariant, const); +CHECK_GET(QVariant, &); +CHECK_GET(QVariant, const &); +CHECK_GET(QVariant, &&); +CHECK_GET(QVariant, const &&); + // check for a type derived from QVariant: struct MyVariant : QVariant @@ -30,7 +38,13 @@ struct MyVariant : QVariant CHECK_GET_IF(MyVariant, /* unadorned */); CHECK_GET_IF(MyVariant, const); +CHECK_GET(MyVariant, &); +CHECK_GET(MyVariant, const &); +CHECK_GET(MyVariant, &&); +CHECK_GET(MyVariant, const &&); + #undef CHECK_GET_IF +#undef CHECK_GET #undef CHECK_IMPL #include <QTest> @@ -368,6 +382,10 @@ private slots: void getIf_QString() { getIf_impl(u"string"_s); }; void getIf_NonDefaultConstructible(); + void get_int() { get_impl(42); } + void get_QString() { get_impl(u"string"_s); } + void get_NonDefaultConstructible(); + private: using StdVariant = std::variant<std::monostate, // list here all the types with which we instantiate getIf_impl: @@ -377,6 +395,8 @@ private: >; template <typename T> void getIf_impl(T t) const; + template <typename T> + void get_impl(T t) const; void dataStream_data(QDataStream::Version version); void loadQVariantFromDataStream(QDataStream::Version version); void saveQVariantFromDataStream(QDataStream::Version version); @@ -5688,12 +5708,14 @@ void tst_QVariant::copyNonDefaultConstructible() QVERIFY(var.constData() != &ndc); // qvariant_cast<T> and QVariant::value<T> don't compile - QCOMPARE(*static_cast<const NonDefaultConstructible *>(var.constData()), ndc); + QCOMPARE(get<NonDefaultConstructible>(std::as_const(var)), ndc); QVariant var2 = var; var2.detach(); // force another copy QVERIFY(var2.isDetached()); QVERIFY(var2.constData() != var.constData()); + QCOMPARE(get<NonDefaultConstructible>(std::as_const(var2)), + get<NonDefaultConstructible>(std::as_const(var))); QCOMPARE(var2, var); } @@ -5702,6 +5724,11 @@ void tst_QVariant::getIf_NonDefaultConstructible() getIf_impl(NonDefaultConstructible{42}); } +void tst_QVariant::get_NonDefaultConstructible() +{ + get_impl(NonDefaultConstructible{42}); +} + template <typename T> T mutate(const T &t) { return t + t; } template <> @@ -5813,5 +5840,65 @@ void tst_QVariant::getIf_impl(T t) const } } +template <typename T> +void tst_QVariant::get_impl(T t) const +{ + QVariant v = QVariant::fromValue(t); + + // for behavioral comparison: + StdVariant stdv = t; + + #define FOR_EACH_CVREF(op) \ + op(/*unadorned*/, &&) \ + op(&, &) \ + op(&&, &&) \ + op(const, const &&) \ + op(const &, const &) \ + op(const &&, const &&) \ + /* end */ + + + #define CHECK_RETURN_TYPE_OF(Variant, cvref_in, cvref_out) \ + static_assert(std::is_same_v< \ + decltype(get<T>(std::declval<Variant cvref_in >())), \ + T cvref_out \ + >); \ + /* end */ + #define CHECK_RETURN_TYPE(cvref_in, cvref_out) \ + CHECK_RETURN_TYPE_OF(StdVariant, cvref_in, cvref_out) \ + CHECK_RETURN_TYPE_OF(QVariant, cvref_in, cvref_out) \ + /* end */ + FOR_EACH_CVREF(CHECK_RETURN_TYPE) + #undef CHECK_RETURN_TYPE + + #undef FOR_EACH_CVREF + + // const access: + { + auto &&rs = get<T>(std::as_const(stdv)); + QCOMPARE_EQ(rs, t); + + auto &&rv = get<T>(std::as_const(v)); + QCOMPARE_EQ(rv, t); + } + + // mutable access: + { + T t2 = mutate(t); + + auto &&rs = get<T>(stdv); + QCOMPARE_EQ(rs, t); + rs = t2; + auto &&rs2 = get<T>(stdv); + QCOMPARE_EQ(rs2, t2); + + auto &&rv = get<T>(v); + QCOMPARE_EQ(rv, t); + rv = t2; + auto &&rv2 = get<T>(v); + QCOMPARE_EQ(rv2, t2); + } +} + QTEST_MAIN(tst_QVariant) #include "tst_qvariant.moc" |