[Qt-interest] QMetaMethod invocation without compile-time knowledge of the return type
André Fillipe
andref at syst.com.br
Thu Sep 24 15:51:55 CEST 2009
2009/9/24 Thiago Macieira <thiago at kde.org>
>
> Hi André
Hello, Thiago.
> Actually, your introspector knows about QVariants too. That's your clue.
Certainly!
> Hmm... you're confusing things.
>
> QReturnArgument is a template class. QGenericReturnArgument isn't.
Thank you! That solves it all. I read the Q_RETURN_ARG definition a
bit too quickly and jumped to a wrong conclusion.
> Chained access will be very difficult. Once you make a call, you get an opaque
> QVariant.
The introspector contract requires that any value appearing in the
middle of the path expression be a QObject. If the client disobeys the
contract, well, too bad. I might add special treatment for other
cases, but I'm working primarily with QObjects. Based on your
following advice, the contract will have to be a little bit stricter
but will also encourage proper coding of QObject derivatives. I'm OK
with that. ;)
> If all your return types are pointers to classes deriving primarily and non-
> virtually from QObject, you can try something like this then:
>
> QObject *pointer;
> QGenericReturnArgument returnArg("Author*", &pointer);
> QMetaObject::invokeMethod(obj, "authorAt", returnArg, Q_ARG(int, 2));
Only using QMetaMethod::typeName() to construct the QGenericReturnArg,
instead of the string literal.
> This is *technically* equivalent to the C++ code:
>
> union { QObject *obj; Author *auth; } ptr;
> ptr.auth = obj->authorAt(2);
> use(ptr.obj);
>
> It's not technically equivalent to:
> QObject *obj2 = obj->authorAt(2);
> use(obj2);
>
> Please note the slight but important difference. When you assign an Author* to
> a QObject*, the compiler will generate the necessary pointer adjustments so
> that the QObject pointer points to the QObject sub-object inside the Author
> object. If you use the union, then the pointers will have the same value, but
> will not necessarily be correct.
I spent a bit too much time in Javaland and forgot about multiple
inheritance. Thanks for the reminder.
> I'm pointing this out to note that it isn't a generic solution. However, in
> the case of classes that have a Q_OBJECT tag, moc will complain if the QObject
> sub-object is not at offset zero. In other words, if you use Q_OBJECT, then the
> trick above is safe.
I just love the moc. :) To be sure, this "derive primarily from
QObject" predicate is transitive, right? I mean, if:
class ClassA : public QObject, public AnotherClass, public AndAnother
{
Q_OBJECT
// ...
};
class ClassB : public ClassA, public GimmeSomeDiamonds
{
Q_OBJECT
// ...
};
both ClassA and ClassB will have the QObject sub-object at offset zero.
> It's not even necessary to provide the type name at all, if you call
> qt_metacall directly. But please don't do that because in Qt 4.6 the semantics
> of the meta call have changed slightly:
>
> QVariant outArg; // initialised to QVariant(2) somewhere else
> QObject *returnArg;
> void *array[] = { &returnArg, const_cast<void*>(outArg.constData()) };
>
> obj->qt_metacall(QMetaObject::InvokeMetaMethod, methodId, array);
> use(returnArg);
I noticed that QMetaMethod::invoke() does a lot of type checking using
the type names before delegating to qt_metacall and I didn't want to
lose (or even worse, redo) all that hard work. I prefer to keep away
from qt_metacall for now.
> See also:
> http://qt.gitorious.org/qt/qt/blobs/master/src/dbus/qdbusintegrator.cpp#line808
> and lines 869, 890
I spent a couple hours last night reading QtDBus code, but for another
purpose: redefining the behavior of the property accessors. The stuff
QtDBus does using qt_metacall is simply amazing.
Thank you a lot, Thiago!
--
André
More information about the Qt-interest-old
mailing list