> 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

Reply via email to