summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qvariant.cpp19
-rw-r--r--src/corelib/kernel/qvariant.h22
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp89
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"