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>
This commit is contained in:
parent
79ae79d05c
commit
8983225d3c
@ -2721,6 +2721,12 @@ QT_WARNING_POP
|
||||
\sa fromValue()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\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
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user