[Development] QMetaType and non-const references

Thiago Macieira thiago.macieira at intel.com
Tue Jul 19 17:01:20 CEST 2022

On Monday, 18 July 2022 23:54:13 PDT Ulf Hermann wrote:
> Hi,
> for the purpose of QML support, the types of properties and the
> arguments and return types of invokable methods, signals, and slots have
> to be available as metatypes. We need _all_ types with metaobjects to
> observe this rule, not only the ones explicitly registered with the
> QML_* macros. This is because:
> a, You can have properties and methods in a base type and expose a
> derived type to QML. The properties and methods of the base type should
> still be available in QML.

Right now, if moc detects the  QML macros in the class definition, it forces 
the method parameters to be fully defined, not just forward declarations. But 
in your case here, the derived class without the macro or the parent will not 
get such a treatment and any type that is only forward declared will be 
missing a metatype. I'm not changing this.

Right now, a metatype for a non-const reference is mistakenly saved as the 
metatype for the const reference / base type. I'm fixing this.

> b, You can separate the QML registration from the type declaration with
> QML_FOREIGN. The QML_FOREIGN can live in a different library, and can
> even be written in the future.

Can you explain a little more what this is for?

> QML has no use for non-const references right now. If those are
> encountered, QML should refuse to touch the property or method. (In
> fact, QML might treat them as synonymous to const references right now,
> but that would be a bug).

Ok, same bug as current metatype, so it'll get fixed by refusing to form the 
metatype in the first place and thus not record it in the meta object.

> In the same way, types without copy-ctor are unsupported right now.
> QML's value type wrapper assumes that it can copy values around (wrapped
> in QVariant for the most part). I can't rule out that someone has found
> some trickery to use then in a place _I_ don't see right now, but at the
> moment non-copiable types are not very useful in QML, either.

QVariant will not change: it will require default-constructible, copyable and 
destructible types. Any acceptance of a metatype that isn't one of those is a 

By the way, do you need the metatype for the QObject-derived class, or do you 
need the metatype for the pointer to that class? There's a mighty difference 
(QObjects can't be copied, sometimes they don't have accessible default 
constructors), including because the extraction in QMetaType flag is 
"IsPointerTOQObject", not "IsQObject".

> However, I can see the _possibility_ of supporting movable and
> default-constructible but non-copiable types. Once we have syntax for
> constructing value types in QML, we might allow assigning such things to
> properties.

QMetaType extracts the move constructor, but has no front-end methods for it 
and QVariant doesn't use them right now either. So that would be a whole new 

> Furthermore, if I have the metatypes available, I can come up with more
> interesting functionality in the future (for example making QML's value
> type references actual references). So, if it's not horribly
> complicated, I would indeed like as many metatypes as possible to be
> available.

Ok, thanks. What about rvalue references?

> Furthermore, I can definitely see a use for a QVariant "move-ctor" that
> takes a T&& or moves out of another QVariant or out of a non-const
> void*. I could use it already today in the code qmlcachegen generates.
> Restricting such a thing to copiable types would be a bit silly. I know
> you want to keep the specifics of this discussion out of this thread,
> but this is another case for move-only types retaining their metatypes.

Thanks, see above, new feature.

> So, I will amend your proposal a bit:
> > - reject them [non-const refs] in QMetaType::fromType, since they're
> > usually not what you wanted. See
> > https://codereview.qt-project.org/c/qt/qtquick3d/+/422197
> OK, if it has to be done. But don't prevent a future implementation of
> QMetaType::fromReference or similar. We might even come up with a
> QMetaType::fromRValue. One of those may be what you need below.

That was the intention (maybe QMetaType::forReference).

To the people who do generic programming, do you see a problem with this?

> > - reject non-default constructible, non-copyable or non-destructible types
> > in QVariant but not QMetaType -- this includes non-const references
> > 
> > 	=> corollary: need a way to form them, but not QMetaType::fromType.
> Right now this is probably the correct thing to do. However, once we
> allow moving into and out of QVariant, we should revise this.

Movable but not copyable or not default constructible?

QMetaType could support them directly. The construct/create operations are 
independent from destroy/destruct, or from each other. If a type today is not 
default constructible, but is copyable, QMetaType *can* copy it onto a new 
void* array of yours. That same does not extend to QVariant today.

> > - do use them in QMetaObject for reporting purposes
> I understand this as "Properties and method arguments or return values
> of such types will still have metatypes." I agree.


> > - add a way to link a T& metatype back to T's
> That may be useful. I don't have much of an opinion here.

I think it goes without saying this needs to be a two-way link. However, the 
existence of such a link may prevent QMetaType::for/fromReference<T &> from 
working if T is also only forward-declared. We do use this frequently, as in:

	const QString &

Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering

More information about the Development mailing list