Details
-
Bug
-
Resolution: Done
-
P2: Important
-
5.8.0 RC
-
None
-
Qt 5.8.0 RC, any OS
Description
In Qt 5.8 we see many changes, and one of these is std::nullptr_t became registered type which is meant to be use for null values.
So, for example, if in C++ we get QVariant value from QML, and this value was set to null in QML, then QVariant::isNull() returns false. And user has to write ugly code like this:
if(value.isNull() || static_cast<QMetaType::Type>(value.type()) == QMetaType::Nullptr) { // The value is null, or default object for a type } else { // In this branch we can try convert value to C++ types }
instead of something like this:
if(value.isNull()) { // The value is null, or default object for a type } else { // In this branch we can try convert value to C++ types }
Other example is:
int main() { QVariant v1 = QVariant::fromValue<void*>(nullptr); QVariant v2 = QVariant::fromValue(nullptr); qDebug() << v1.isNull() << v2.isNull() << (v1 == v2) << (v2 == v1); qDebug() << v2.canConvert<void*>() << v2.canConvert<QObject*>(); } // output: // "false false false false" // "false false"
I agree with the author of this example (Olivier) and I also think that it is wrong. Because it goes against of semantic of the isNull() method name.
In the discussion there are some posts against Olivier, but I think it is better for future releases to fix it now.
One of the possible solutions is based on the post:
QVariant's only pointer constructor is the one for const char*, which will be
null if the pointer is null too. That would support the proposition that
QVariant(nullptr).isNull() because QVariant((const char*)nullptr).isNull().However, to create a VoidStar, you need to write:
QVariant::fromValue<void *>(nullptr);
which does
return QVariant(qMetaTypeId<T>(), &t, QTypeInfo<T>::isPointer);
That constructor always sets d.is_null = false. So the QVariant is not null,
as it contains a valid VoidStar value. It just happens that the VoidStar
itself is null. In other words, QVariant behaves like a non-null void**
pointing to a null void*.
So, maybe it should check the pointer value in QVariant(qMetaTypeId<T>(), &t, QTypeInfo<T>::isPointer) constructor and if isPointer and *t is null then set d.is_null = true
P.S. You could read the discussion in these links:
http://lists.qt-project.org/pipermail/development/2016-September/027370.html
http://development.qt-project.narkive.com/YnH0ceXV/behaviour-change-in-qml-in-qt-5-8-regarding-null
P.P.S. I think it must to be fixed before the final release of Qt 5.8.0, because later it will harder to change the behavior in public API, IMHO.