QVariant: Add support for in-place construction
This avoids constructing an object just to copy (later: move) it into a QVariant. ChangeLog will be in a follow-up change adding emplace support. Task-number: QTBUG-112187 Change-Id: I444e580c7d8927d41b3d21d5a521e7c475119e4c Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
parent
6e5258b48b
commit
c81e8f8ff2
@ -523,6 +523,43 @@ QVariant::QVariant(const QVariant &p)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn template <typename Type, typename... Args, if_constructible<Type, Args...> = true> QVariant::QVariant(std::in_place_type_t<Type>, Args&&... args) noexcept(is_noexcept_constructible<q20::remove_cvref_t<Type>, Args...>::value)
|
||||
|
||||
\since 6.6
|
||||
Constructs a new variant containing a value of type \c Type. The contained
|
||||
value is is initialized with the arguments
|
||||
\c{std::forward<Args>(args)...}.
|
||||
|
||||
This overload only participates in overload resolution if \c Type can be
|
||||
constructed from \a args.
|
||||
|
||||
This constructor is provided for STL/std::any compatibility.
|
||||
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
||||
\fn template <typename Type, typename List, typename... Args, if_constructible<Type, std::initializer_list<List> &, Args...> = true> explicit QVariant::QVariant(std::in_place_type_t<Type>, std::initializer_list<List> il, Args&&... args) noexcept(is_noexcept_constructible<q20::remove_cvref_t<Type>, std::initializer_list<List> &, 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.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QVariant::QVariant(const QString &val) noexcept
|
||||
|
||||
|
@ -62,6 +62,15 @@ template<> constexpr inline bool qIsRelocatable<QVariant> = true;
|
||||
}
|
||||
class Q_CORE_EXPORT QVariant
|
||||
{
|
||||
template <typename Type, typename... Args>
|
||||
using if_constructible = std::enable_if_t<
|
||||
std::conjunction_v<
|
||||
std::is_copy_constructible<q20::remove_cvref_t<Type>>,
|
||||
std::is_destructible<q20::remove_cvref_t<Type>>,
|
||||
std::is_constructible<q20::remove_cvref_t<Type>, Args...>
|
||||
>,
|
||||
bool>;
|
||||
|
||||
struct CborValueStandIn { qint64 n; void *c; int t; };
|
||||
public:
|
||||
struct PrivateShared
|
||||
@ -204,6 +213,37 @@ public:
|
||||
explicit QVariant(QMetaType type, const void *copy = nullptr);
|
||||
QVariant(const QVariant &other);
|
||||
|
||||
private:
|
||||
template<typename Type, typename ...Args>
|
||||
using is_noexcept_constructible = std::conjunction<
|
||||
std::bool_constant<Private::CanUseInternalSpace<Type>>,
|
||||
std::is_nothrow_constructible<Type, Args...>
|
||||
>;
|
||||
|
||||
public:
|
||||
template <typename Type, typename... Args,
|
||||
if_constructible<Type, Args...> = true>
|
||||
explicit QVariant(std::in_place_type_t<Type>, Args&&... args)
|
||||
noexcept(is_noexcept_constructible<q20::remove_cvref_t<Type>, Args...>::value)
|
||||
: QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<Type>>() )
|
||||
{
|
||||
void *data = const_cast<void *>(constData());
|
||||
new (data) Type(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Type, typename List, typename... Args,
|
||||
if_constructible<Type, std::initializer_list<List> &, Args...> = true>
|
||||
explicit QVariant(std::in_place_type_t<Type>, std::initializer_list<List> il, Args&&... args)
|
||||
noexcept(is_noexcept_constructible<q20::remove_cvref_t<Type>,
|
||||
std::initializer_list<List> &,
|
||||
Args...
|
||||
>::value)
|
||||
: QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<Type>>())
|
||||
{
|
||||
char *data = static_cast<char *>(const_cast<void *>(constData()));
|
||||
new (data) Type(il, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// primitives
|
||||
QVariant(int i) noexcept;
|
||||
QVariant(uint ui) noexcept;
|
||||
@ -535,6 +575,9 @@ private:
|
||||
// int variant, so delete this constructor:
|
||||
QVariant(QMetaType::Type) = delete;
|
||||
|
||||
// used to setup the QVariant internals for the "real" inplace ctor
|
||||
QVariant(std::in_place_t, QMetaType type);
|
||||
|
||||
// These constructors don't create QVariants of the type associated
|
||||
// with the enum, as expected, but they would create a QVariant of
|
||||
// type int with the value of the enum value.
|
||||
|
@ -378,6 +378,8 @@ private slots:
|
||||
void constructFromIncompatibleMetaType();
|
||||
void copyNonDefaultConstructible();
|
||||
|
||||
void inplaceConstruct();
|
||||
|
||||
void getIf_int() { getIf_impl(42); }
|
||||
void getIf_QString() { getIf_impl(u"string"_s); };
|
||||
void getIf_NonDefaultConstructible();
|
||||
@ -5720,6 +5722,23 @@ void tst_QVariant::copyNonDefaultConstructible()
|
||||
QCOMPARE(var2, var);
|
||||
}
|
||||
|
||||
void tst_QVariant::inplaceConstruct()
|
||||
{
|
||||
{
|
||||
NonDefaultConstructible ndc(42);
|
||||
QVariant var(std::in_place_type<NonDefaultConstructible>, 42);
|
||||
QVERIFY(get_if<NonDefaultConstructible>(&var));
|
||||
QCOMPARE(get<NonDefaultConstructible>(var), ndc);
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> vec {1, 2, 3, 4};
|
||||
QVariant var(std::in_place_type<std::vector<int>>, {1, 2, 3, 4});
|
||||
QVERIFY(get_if<std::vector<int>>(&var));
|
||||
QCOMPARE(get<std::vector<int>>(var), vec);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QVariant::getIf_NonDefaultConstructible()
|
||||
{
|
||||
getIf_impl(NonDefaultConstructible{42});
|
||||
|
Loading…
Reference in New Issue
Block a user