[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