[Development] QProperty and library coding guide

Ulf Hermann ulf.hermann at qt.io
Fri Jul 17 15:01:31 CEST 2020

>>>> QAction *action = ~~~;
>>>> auto prop = action->text;
>> This already gives you the string. You cannot retrieve the property
>> itself. You can alternatively do action->text() or action->text.value().
>> They all do the same thing.
> Uhm... sorry, no, this doesn't really compute for me. Ignore the copy 
> semantics for a second (use const auto &, if necessary), what's 
> decltype(prop)? If it's QString, then you can't write .value() after it.

OK, I got you wrong, and I was confused about the cast operators in 
QProperty and the property wrappers. Sorry. Indeed "auto prop = 
action->text;" would give you a useless object that pokes random memory 
whenever you invoke any method of it. That needs to be fixed indeed. You 
should not be able to copy the property wrapper out of the object. For 
properties on QObject that would be easy as QObject itself is not 
copyable. We could just =delete the copy ctor and assignment operators. 
We might also prevent external construction of the struct by having some 
"secret" extra argument, kind of like QPrivateSignal.

However, for Q_GADGET this would fall apart.

For reference, Q_PRIVATE_QPROPERTY looks like this:

#define Q_PRIVATE_QPROPERTY(accessor, type, name, setter, ...) \
             struct _qt_property_api_##name { \
                 type value() const; \
                 type operator()() const { return value(); } \
                 void setValue(type &&); \
                 void setValue(type const &); \
                 void operator=(type const &v) { setValue(v); } \
                 void operator=(type &&v) { setValue(std::move(v)); } \
                 QPropertyBinding<type> setBinding(const 
QPropertyBinding<type> &); \
setBinding(QPropertyBinding<type> &&); \
                 QPropertyBinding<type> operator=(const 
QPropertyBinding<type> &b) { return setBinding(b); } \
                 QPropertyBinding<type> operator=(QPropertyBinding<type> 
&&b) { return setBinding(std::move(b)); } \
                 bool setBinding(const QUntypedPropertyBinding &); \
                 template <typename Functor> \
                 QPropertyBinding<type> setBinding(Functor f, \
QPropertyBindingSourceLocation &location = 
                 { \
                     return setBinding(Qt::makePropertyBinding(f, 
location)); \
                 } \
                 bool hasBinding() const; \
                 QPropertyBinding<type> binding() const; \
                 QPropertyBinding<type> takeBinding(); \
             }; \
             void setter(type const& value);

So, in fact we need to rework this and provide only methods instead of a 
struct. Now we need a naming convention for all those methods and some 
way of avoiding name clashes.

If QNotifiedProperty didn't need members of the private object as 
template parameters, we could just have one extra method that retrieves 
a reference to the underlying Q(Notified)Property (or rather two: const 
and non-const).

> No, actually this makes perfect sense, but was contradicted before:
>> We are not casting these structs to or from anything though, do we?

That statement was wrong. We do need to cast the structs. Another 
argument for eliminating them.


More information about the Development mailing list