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>
This commit is contained in:
Fabian Kosmale 2020-07-15 14:12:58 +02:00 committed by Lars Knoll
parent 52bbb19fa4
commit 733d890430
4 changed files with 70 additions and 13 deletions

View File

@ -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>

View File

@ -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));

View File

@ -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>) {

View File

@ -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;