[Qt5-feedback] Relaxing constraints for registering types with QMetaType

Craig.Scott at csiro.au Craig.Scott at csiro.au
Wed Jun 1 02:43:09 CEST 2011


Since this list has quietened down a bit over the past few days, I thought it would be a good time to throw this one into the mix for Qt5 discussion. The motivation for attaching the following to the Qt5 discussion is because it relates to specifics of binary compatibility and there is potential for changes made for Qt5 to impact the viability of the techniques discussed. For reference, full details for the following cat be found in issue QTBUG-15313.

The QMetaType documentation contains the following statement when talking about what types can be registered with QMetaType:

"Any class or struct that has a public default constructor, a public copy constructor, and a public destructor can be registered."

Looking more closely through the code for QMetaType and QVariant reveals why these restrictions exist, but it also reveals that the restrictions are unnecessary! There are some helper templates defined in the qmetatype.h header (specifically qMetaTypeConstructHelper() and qMetaTypeDeleteHelper()) which rely on these assumptions, but since they are templates, there's no reason why explicit specializations could not be provided to give alternative implementations that did not require the above-mentioned constraints. If I wanted to register a type that had a clonable interface but no copy constructor, I could provide an explicit specialization of qMetaTypeConstructHelper() which used the cloning mechanism instead of a copy constructor. Similarly, if my type had some kind of destroy() function instead of a public destructor, I could do a similar thing with qMetaTypeDeleteHelper().

The other place where this restriction comes up is in QVariant::value<T>(), which returns by value, not by reference. This is because it may need to convert from the underlying type to the requested type. (The implementation of this function calls qVariantValue() and qvariant_cast() which are both template functions that also return by value). If, however, the underlying type and the requested type are the same, this involves copies that could be avoided. In this situation, QVariant::constData() (or potentially QVariant::data()) could be used to access the underlying data without having to copy it. Currently, QVariant::constData() is not documented as being part of the public API, but it effectively *is* part of the public API because inlined templates in the qvariant.h header call it and hence it has to be available to preserve binary compatibility.

What all this means is that if a developer wants to register a type that does not satisfy the constructor and destructor requirements, they can supply their own qMetaTypeConstructHelper() and/or qMetaTypeDeleteHelper() template specializations. They could then also choose to either have their type not support QVariant::value() (which would be a compile-time error) or they could also provide a specialization for QVariant::value() as well. And there is one important aspect to all this:

NO CHANGE WOULD BE REQUIRED TO ANY QT CODE AND THIS WORKS BACK AT LEAST AS FAR AS QT 4.5. ALL THAT WOULD NEED ALTERING IS THE QT DOCUMENTATION!!!

My main reason for bringing this up here on this list is that I'd like to see the above continue to be possible in Qt5. We do exactly what is discussed above in our own code, and we know it has to be safe for as long as Qt preserves binary compatibility. It is a very useful technique, particularly where your code wants to make use of QtScript (QVariants become quite useful in that context when passing data to/from C++). This idea didn't get much love in the bug report, but I'd like to see it at least considered in the Qt5 context. After all, it really only requires documenting things that are required for preserving binary compatibility anyway!

--
Dr Craig Scott
Computational Software Engineering Team Leader, CSIRO (CMIS)
Melbourne, Australia





More information about the Qt5-feedback mailing list