diff options
-rw-r--r-- | src/corelib/global/qtypeinfo.h | 10 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty.h | 42 | ||||
-rw-r--r-- | src/corelib/kernel/qpropertyprivate.h | 2 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp | 29 |
4 files changed, 70 insertions, 13 deletions
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h index 30db5c4487..c0617a41f2 100644 --- a/src/corelib/global/qtypeinfo.h +++ b/src/corelib/global/qtypeinfo.h @@ -324,6 +324,16 @@ struct expand_operator_less_than_tuple<std::variant<T...>> : expand_operator_les } +template<typename T, typename = void> +struct is_dereferenceable : std::false_type {}; + +template<typename T> +struct is_dereferenceable<T, std::void_t<decltype(std::declval<T>().operator->())> > + : std::true_type {}; + +template <typename T> +constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value; + template<typename T> struct has_operator_equal : detail::expand_operator_equal<T> {}; template<typename T> diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index acaf74f9af..ff61596fb6 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -192,8 +192,15 @@ struct QPropertyBasePointer; template <typename T> class QProperty { + class DisableRValueRefs {}; + static constexpr bool UseReferences = !(std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_pointer_v<T>); + public: using value_type = T; + using parameter_type = std::conditional_t<UseReferences, const T &, T>; + using rvalue_ref = typename std::conditional_t<UseReferences, T &&, DisableRValueRefs>; + using arrow_operator_result = std::conditional_t<std::is_pointer_v<T>, const T &, + std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, const T &, void>>; QProperty() = default; explicit QProperty(const T &initialValue) : d(initialValue) {} @@ -218,7 +225,7 @@ public: #endif ~QProperty() = default; - T value() const + parameter_type value() const { if (d.priv.hasBinding()) d.priv.evaluateIfDirty(); @@ -226,32 +233,49 @@ public: return d.getValue(); } - operator T() const + arrow_operator_result operator->() const + { + if constexpr (QTypeTraits::is_dereferenceable_v<T>) { + return value(); + } else if constexpr (std::is_pointer_v<T>) { + value(); + return this->val; + } else { + return; + } + } + + parameter_type operator*() const { return value(); } - void setValue(T &&newValue) + operator parameter_type() const + { + return value(); + } + + void setValue(rvalue_ref newValue) { d.priv.removeBinding(); if (d.setValueAndReturnTrueIfChanged(std::move(newValue))) notify(); } - void setValue(const T &newValue) + void setValue(parameter_type newValue) { d.priv.removeBinding(); if (d.setValueAndReturnTrueIfChanged(newValue)) notify(); } - QProperty<T> &operator=(T &&newValue) + QProperty<T> &operator=(rvalue_ref newValue) { setValue(std::move(newValue)); return *this; } - QProperty<T> &operator=(const T &newValue) + QProperty<T> &operator=(parameter_type newValue) { setValue(newValue); return *this; @@ -263,12 +287,6 @@ public: return *this; } - QProperty<T> &operator=(QPropertyBinding<T> &&newBinding) - { - setBinding(std::move(newBinding)); - return *this; - } - QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding) { QPropertyBinding<T> oldBinding(d.priv.setBinding(newBinding, &d)); diff --git a/src/corelib/kernel/qpropertyprivate.h b/src/corelib/kernel/qpropertyprivate.h index d5ee9f29c2..4d8a457e32 100644 --- a/src/corelib/kernel/qpropertyprivate.h +++ b/src/corelib/kernel/qpropertyprivate.h @@ -136,7 +136,7 @@ public: QPropertyValueStorage(QPropertyValueStorage &&other) : value(std::move(other.value)), priv(std::move(other.priv), this) {} QPropertyValueStorage &operator=(QPropertyValueStorage &&other) { value = std::move(other.value); priv.moveAssign(std::move(other.priv), &value); return *this; } - T getValue() const { return value; } + T const& getValue() const { return value; } bool setValueAndReturnTrueIfChanged(T &&v) { if constexpr (QTypeTraits::has_operator_equal_v<T>) { diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp index 74a81cc93b..20565080ff 100644 --- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp +++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp @@ -69,6 +69,7 @@ private slots: void setBindingFunctor(); void multipleObservers(); void propertyAlias(); + void arrowAndStarOperator(); void notifiedProperty(); void notifiedPropertyWithOldValueCallback(); void notifiedPropertyWithGuard(); @@ -753,6 +754,34 @@ void tst_QProperty::propertyAlias() QCOMPARE(value2, 22); } +void tst_QProperty::arrowAndStarOperator() +{ + QString str("Hello"); + QProperty<QString *> prop(&str); + + QCOMPARE(prop->size(), str.size()); + QCOMPARE(**prop, str); + + struct Dereferenceable { + QString x; + QString *operator->() { return &x; } + const QString *operator->() const { return &x; } + }; + static_assert(QTypeTraits::is_dereferenceable_v<Dereferenceable>); + + QProperty<Dereferenceable> prop2(Dereferenceable{str}); + QCOMPARE(prop2->size(), str.size()); + QCOMPARE(**prop, str); + + QObject *object = new QObject; + object->setObjectName("Hello"); + QProperty<QSharedPointer<QObject>> prop3(QSharedPointer<QObject>{object}); + + QCOMPARE(prop3->objectName(), str); + QCOMPARE(*prop3, object); + +} + struct ClassWithNotifiedProperty { QList<int> recordedValues; |