> On 20 Jul 2023, at 16:17, Fabian Kosmale via Development > <development@qt-project.org> wrote: >> Hi everyone, >> >> something that came up during this year’s KDE Akademy was that we >> believe Q_PROPERTY should be able to handle std::optional, such that you >> get a null QVariant out of it if it has no value. The main use case >> being interfacing “more modern C++” with QML in a type-safe way, rather >> than using QJSValue::Undefined for invalid results. >>
[…] >> Is that something that we would like to see? I was told that a QMetaType >> is “full” and version bump needs to happen first before it can be >> extended or something? >> >> Cheers >> Kai Uwe > > Hi, > > as far as QMetaType is concerned: We need a way to have some introspection on > the "contained" type. That can't really be shoehorned into the current > QMetaTypeInterface, because that one has neither enough space, nor a > useable function pointer that could be hijacked. > However, incrementing the QMetaTypeInterface revision and appending a new > member is possible (QMTI has been written with extensibility in mind), and > then > you can add another function pointer to e.g. retrieve QMetaType::fromType<T>() > if you have QMetaType::fromType<std::optional<T>>. Gettnig that in should be > mostly straightforward. […] > In general, I think having a way to expose optional value in a nice way is > worthwhile, but I'm currently not sure what the best way forward would be. Agree that supporting std::optional would be useful! > At the QML layer, we would need to have some discussion on how to map the > values. Should a std::optional<T> be "undefined if it's nullopt, and behave > like Q_PROPERTY of type T otherwise"? With `maybeValue` being a `Q_PROPERTY(std::optional<T> …)`, object->property(“maybeValue”); would return a null-QVariant if the property is nullopt, which maps to undefined in QML. But should it hold a std::optional<T> or a T otherwise? QML needs a T; and on the C++ side we should probably keep the complete type information (and .value<T>() will have to return the same thing either way). How about conversion: QVariant(std::optional<T>>).value<U>(); // return U{} if T cannot be converted; otherwise U(T); QVariant().value<std::optional<T>>(); // nullopt, not a std::optional holding a T{} QVariant(42).value<std::optional<int>>(); // std::optional holding 42 QVariant(QSize()).value<std::optional<int>>(); // probably nullopt? > That would mostly work, unless you want > a RESETable property, where RESET shouldn't lead to a nullopt value. Reseting a property should reset to what it was when the object was newly constructed, which would probably have been nullopt. Why is it problematic it RESETing a std::optional produces something else than nullopt? > Should nullopt be mapped to null instead (but then you can't distinguish > nullopt and nullptr). Or should we have optional<T> in QML in the same > way we have list<T>? That would require defining its interaction with > JS code. Setting such a property to undefined should produce a std::nullopt on the C++ side, I think. And symmetrically, the value of a nullopt property should be undefined on the QML/JS side. >> The question is also, where do we draw the line: I could see a use for >> having an std::variant property for when we have a known set of types we >> accept (e.g. std::variant<QString, QIcon>). Again something where we >> currently would do a QVariant with manual conversions and missing >> introspection. Can you elaborate on that? What kind of introspection are you missing? Are you looking for a type-error on the caller (i.e. QML) side? E.g. if the property is of type std::variant<QString, QIcon>, and QML tries to set it to something else? What if that “something else" can be converted to a QString? Volker -- Development mailing list Development@qt-project.org https://lists.qt-project.org/listinfo/development