summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-07-15 14:12:58 +0200
committerLars Knoll <lars.knoll@qt.io>2020-09-02 22:44:27 +0200
commit733d890430542e907b9014a2cf73d63edf931245 (patch)
tree470dd4321b748c0de57b182617950321b7f22731
parent52bbb19fa4dc7647a0cad35a69dcf09437386080 (diff)
Add operator-> and operator*() to QProperty
Enable the arrow operator for all types that could have members, so that one can e.g. write myStringProperty->size() instead of having to use the less convenient myStringProperty.value().size(). Also cleaned up the rvalue ref overloads to be disabled for basic types. For those we now also return by value, for more complex types we return a const reference. Change-Id: If6a75898dc0a097f57052488f0af0cd7166b3393 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/corelib/global/qtypeinfo.h10
-rw-r--r--src/corelib/kernel/qproperty.h42
-rw-r--r--src/corelib/kernel/qpropertyprivate.h2
-rw-r--r--tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp29
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;