[Interest] Creating a QVariant of QList<QObject*> knowing only the class name
Thiago Macieira
thiago.macieira at intel.com
Wed Feb 22 08:58:14 CET 2017
On terça-feira, 21 de fevereiro de 2017 18:20:50 PST Ch'Gans wrote:
> Hi there,
>
> I can create a valid QVariant that contains a MyObject pointer with
> just the class name (ie, QString("MyObject")) and no access to the
> class declaration. MyObject is derived from QObject.
>
> This QVariant has the following properties:
> - type() == QVariant::UserType
> - userType() == QMetaType::type("MyObject*")
This variant will have no content. Its isNull() method will return true.
You can call the QVariant constructor that takes a void* object to the data,
so it will copy when creating the object. This is easy because "MyObject*" is,
like its name shows, a pointer. We all know how to copy pointers.
> The consumer of this variant, which has access to the original class
> declaration, can obtain a valid pointer with
> variant.value<MyObject*>()
Correct.
> Now I need to create a QVariant that contains a QList<MyObject*> with
> just the class name (ie, QString("MyObject")) and no access to the
> class declaration.
>
> Again the resulting variant needs to have the following properties:
> - type() == QVariant::UserType
> - userType() == QMetaType::type("QList<MyObject*>")
Ok, same thing, same solution.
> My question is how do I create and "populate" such a variant without
> using template involving MyObject*?
Forget templates. They don't exist at the level of QVariant. Only concrete
types do.
For the sake of the argument, let's call it "MyObjectList". It's not a pointer
and it's not a built-in type.
> QSequentialIterable allows one to iterate on such a variant, but only
> provide a const access, so it is useless in my case.
>
> I seem to have found a solution, but i'm not sure it is correct and safe:
> QList<QObject*> list;
> // populate the list with MyObject* items
> int desiredMetaTypeId = QMetaType::type("QList<MyObject*>")
> return QVariant(desiredMetaTypeId, &list);
It's not correct. Whether it's safe or not, I won't answer, because you
shouldn't be doing it in the first place. Qt has a few hacks that cast a QList
of one type to a QList of another type (a concept called "covariance"), but
this is a very ugly hack, should never be done like that, and only works in Qt
because Qt itself controls QList and we can know whether the structure layout
is compatible. But from the strict C++ point of view, it's invalid and a
future compiler could just break that code.
So, don't write it.
If you're going to call the QVariant constructor with a pointer, you MUST pass
a pointer to the correct, concrete object. Forget that it was a template: just
think of it as "MyObjectList" that has absolutely no relationship with
QObjectList.
> Does anyone know a "proper" solution for this? Or is my approach
> correct and safe?
Your approach is to redesign and think the problem from another angle.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
More information about the Interest
mailing list