除非之前调用过 QVariant::fromValue<T>(),否则 QVariant::value<T>() 无法转换。这是预期的行为吗?

Gus*_*o Q 5 c++ qt qt6

在 Windows 下使用 Qt 6.2.1 和 Microsoft MSVC 2019。

给定此函数从持久设置中加载无符号整数列表:

QList<uint> get(QSettings& settings, QString& key) {
    QVariant v {settings.value(key)}
    return v.value<QList<uint>>();
}
Run Code Online (Sandbox Code Playgroud)

对 v.value() 的调用有时会无法转换存储在 QVariant 中的值,从而产生以下调试消息:

QVariant::load:名称为 QList<uint> 的未知用户类型

存储列表的反函数总是可以正常工作:

void set(QSettings& settings, QString& key, QList<uint> list) {
    QVariant v {QVariant::fromValue<QList<uint>>(list)};
    settings.setValue(key, v);
}
Run Code Online (Sandbox Code Playgroud)

经过一些调试,我缩小了第一个功能失败的情况。看来它与类型 QList<uint> 的注册元类型及其注册的数据流运算符有关。

如果在程序执行期间,在调用 get() 之前的任何时候至少执行了一次以下代码,则有问题的 QVariant 转换将完成且不会出现错误:

// Either this one
QVariant::fromValue<QList<uint>>(list);
// or these
auto mt = QMetaType::fromType<QList<uint>>();
mt.hasRegisteredDataStreamOperators();
Run Code Online (Sandbox Code Playgroud)

这是设计使然还是 Qt 6 中的错误?

QVariant::value 和 QVariant::fromValue 之间的这种不对称行为令人费解。

现在,我通过添加虚拟调用来强制 MetaType 注册或后台发生的任何事情来解决这个问题:

QVariant::fromValue<QList<uint>>(QList<uint>{}); // Dummy call
return v.value<QList<uint>>();
Run Code Online (Sandbox Code Playgroud)

但这感觉像是一个糟糕的黑客。如果这不是一个错误,肯定有更好的方法。谁能解释一下这个问题?

注意 qRegisterMetaTypeStreamOperators("name") 已在 Qt 6 中删除。

PS:上面的示例代码是我正在处理的实际代码的非常简化的版本。