summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2023-05-31 16:34:01 +0200
committerMarc Mutz <marc.mutz@qt.io>2023-06-02 20:32:11 +0000
commit8983225d3c20967d23b23d3071988a66df4e29f5 (patch)
treefeccea8001a39670a8fff376a350e9a269a780a4
parent79ae79d05c65019233cf9ae9e77ef59d90e75ac2 (diff)
QVariant: add rvalue overload of fromStdVariant()
Extract Method fromStdVariantImpl() to share the otherwise more-or-less identical implementation between the two overloads. Don't use a constrained template version of fromStdVariantImpl() as fromStdVariant(), because the constraint would have to be very complex to continue allowing subclasses of std::variant to be passed. As a drive-by, mark the valueless_by_exception() path Q_UNLIKELY. [ChangeLog][QtCore][QVariant] Added overload of fromStdVariant() taking rvalue std::variant<>s. Fixes: QTBUG-114134 Change-Id: Ia1c7ae93ab421e6689dc9f2d8d0c2295b23cbbf6 Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/corelib/kernel/qvariant.cpp6
-rw-r--r--src/corelib/kernel/qvariant.h21
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp45
3 files changed, 69 insertions, 3 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 8e2457350c..30da12c95b 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -2722,6 +2722,12 @@ QT_WARNING_POP
*/
/*!
+ \fn template<typename... Types> QVariant QVariant::fromStdVariant(std::variant<Types...> &&value)
+ \since 6.6
+ \overload
+*/
+
+/*!
\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 582f135fab..fe99ad6bdd 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -569,9 +569,13 @@ public:
template<typename... Types>
static inline QVariant fromStdVariant(const std::variant<Types...> &value)
{
- if (value.valueless_by_exception())
- return QVariant();
- return std::visit([](const auto &arg) { return QVariant::fromValue(arg); }, value);
+ return fromStdVariantImpl(value);
+ }
+
+ template<typename... Types>
+ static QVariant fromStdVariant(std::variant<Types...> &&value)
+ {
+ return fromStdVariantImpl(std::move(value));
}
template<typename T>
@@ -585,6 +589,17 @@ public:
static QPartialOrdering compare(const QVariant &lhs, const QVariant &rhs);
private:
+ template <typename StdVariant>
+ static QVariant fromStdVariantImpl(StdVariant &&v)
+ {
+ if (Q_UNLIKELY(v.valueless_by_exception()))
+ return QVariant();
+ auto visitor = [](auto &&arg) {
+ return QVariant::fromValue(q23::forward_like<StdVariant>(arg));
+ };
+ return std::visit(visitor, std::forward<StdVariant>(v));
+ }
+
friend inline bool operator==(const QVariant &a, const QVariant &b)
{ return a.equals(b); }
friend inline bool operator!=(const QVariant &a, const QVariant &b)
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index addf7ceec9..23fa969edd 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -5392,6 +5392,16 @@ void tst_QVariant::shouldDeleteVariantDataWorksForAssociative()
void tst_QVariant::fromStdVariant()
{
+#define CHECK_EQUAL(lhs, rhs, type) do { \
+ QCOMPARE(lhs.typeId(), rhs.typeId()); \
+ if (lhs.isNull()) { \
+ QVERIFY(rhs.isNull()); \
+ } else { \
+ QVERIFY(!rhs.isNull()); \
+ QCOMPARE(get< type >(lhs), get< type >(rhs)); \
+ } \
+ } while (false)
+
{
typedef std::variant<int, bool> intorbool_t;
intorbool_t stdvar = 5;
@@ -5399,21 +5409,38 @@ void tst_QVariant::fromStdVariant()
QVERIFY(!qvar.isNull());
QCOMPARE(qvar.typeId(), QMetaType::Int);
QCOMPARE(qvar.value<int>(), std::get<int>(stdvar));
+ {
+ const auto qv2 = QVariant::fromStdVariant(std::move(stdvar));
+ CHECK_EQUAL(qv2, qvar, int);
+ }
+
stdvar = true;
qvar = QVariant::fromStdVariant(stdvar);
QVERIFY(!qvar.isNull());
QCOMPARE(qvar.typeId(), QMetaType::Bool);
QCOMPARE(qvar.value<bool>(), std::get<bool>(stdvar));
+ {
+ const auto qv2 = QVariant::fromStdVariant(std::move(stdvar));
+ CHECK_EQUAL(qv2, qvar, bool);
+ }
}
{
std::variant<std::monostate, int> stdvar;
QVariant qvar = QVariant::fromStdVariant(stdvar);
QVERIFY(!qvar.isValid());
+ {
+ const auto qv2 = QVariant::fromStdVariant(std::move(stdvar));
+ CHECK_EQUAL(qv2, qvar, int); // fake type, they're empty
+ }
stdvar = -4;
qvar = QVariant::fromStdVariant(stdvar);
QVERIFY(!qvar.isNull());
QCOMPARE(qvar.typeId(), QMetaType::Int);
QCOMPARE(qvar.value<int>(), std::get<int>(stdvar));
+ {
+ const auto qv2 = QVariant::fromStdVariant(std::move(stdvar));
+ CHECK_EQUAL(qv2, qvar, int);
+ }
}
{
std::variant<int, bool, QChar> stdvar = QChar::fromLatin1(' ');
@@ -5421,7 +5448,25 @@ void tst_QVariant::fromStdVariant()
QVERIFY(!qvar.isNull());
QCOMPARE(qvar.typeId(), QMetaType::QChar);
QCOMPARE(qvar.value<QChar>(), std::get<QChar>(stdvar));
+ {
+ const auto qv2 = QVariant::fromStdVariant(std::move(stdvar));
+ CHECK_EQUAL(qv2, qvar, QChar);
+ }
}
+ // rvalue fromStdVariant() actually moves:
+ {
+ const auto foo = u"foo"_s;
+ std::variant<QString, QByteArray> stdvar = foo;
+ QVariant qvar = QVariant::fromStdVariant(std::move(stdvar));
+ const auto ps = get_if<QString>(&stdvar);
+ QVERIFY(ps);
+ QVERIFY(ps->isNull()); // QString was moved from
+ QVERIFY(!qvar.isNull());
+ QCOMPARE(qvar.typeId(), QMetaType::QString);
+ QCOMPARE(get<QString>(qvar), foo);
+ }
+
+#undef CHECK_EQUAL
}
void tst_QVariant::qt4UuidDataStream()