QMetaType casting to desired type
-
Hello,
I want to cast an object I receive over network to the specific class that represents that objects structure. The receiver object, before casting, is a generic networking class. I want to achieve that using QMetaType.
Right now I have something like this
// Check for cast compatibility QString className = "ExampleClass" QMetaType targetType = QMetaType::fromName(className.toUtf8()); QMetaType sourceTarget = QMetaType::fromType<NetworkClass>(); bool canConvert = QMetaType::canConvert(sourceTarget , targetType); if (!type.isValid() || !canConvert) { qWarning() << "targetType not valid or can not convert to targetType"; break; } # untill here all works fine ???
What to do after that. I tried a lot of things. All QMetaType functions return void* which I cant do nothing with.
I could write down every possible qobject_cast in a switch statement but I want to keep this as dynamic as possible
-
How is the object transmitted? I had presumed this was for POD classes until the mention of qobject_cast.
As far as doing something with the reconstructed object, what's the goal? Ignoring the transmission question, if the object is QObject derived, the QMetaObject::invoke* and property functions can be used.
If the goal is a symbol referring to a derived type, perhaps a template function accepting a parameter pack of types could return a std::variant or similar and save a little typing.
-
@Asperamanca said in QMetaType casting to desired type:
@Redman
I guess you are missing this code:I saw that, and it surprised me that a sequence of bytes delivered over a network would successfully convert to a QObject.
-
@jeremy_k I'm talking QtRemoteObjects. I intentionally left that piece of information out because every time I mention them in this forum my posts never get answered.
So what exactly is happening?
I have a class ExampleClass
class ExampleClass : public ExampleClassSimpleSource { Q_OBJECT . . .
Which gets remoted via
bool rslt = myRegistry.enableRemoting(&obj);
somewhere in my code.
Retrieving that remoted object via
QSharedPointer<ExampleClassReplica> rep; rep.reset(node.data()->acquire<ExampleClassReplica>(id));
Now, obviously I want to have more classes I can remote than this ExampleClass. But for now I have this solution.
// Enum of my classes which are used as remote objects RO ro = static_cast<T>( QMetaEnum::fromType<RO>().keyToValue(entry.second.typeName.toLocal8Bit())); switch (ro) { case RoReceiver::ExampleClass: { QSharedPointer<ExampleClassReplica> rep; rep.reset(node.data()->acquire<ExampleClassReplica>(id)); // Helps us keep track of the remote objects connect(rep.data(), SIGNAL(removeChanged(bool)), m_instanceTest.data(), SLOT(recRemoveChanged(bool))); connect(rep.data(), &QRemoteObjectReplica::initialized, m_instanceTest.data(), &RoReceiverTest::recInitChanged); // Keep track of available remote objects rep.data()->setObjectName(id); m_instanceTest.data()->m_nodes[node].insert(id, rep); Q_EMIT m_instanceTest.data()->echoRecRemoteObjectTest(rep); return; } break; }
This switch statement is gonna get bigger and bigger aswell as be error prone.
Is there any way to make this piece of code dynamic? -
@jeremy_k said in QMetaType casting to desired type:
@Asperamanca said in QMetaType casting to desired type:
@Redman
I guess you are missing this code:I saw that, and it surprised me that a sequence of bytes delivered over a network would successfully convert to a QObject.
Anything in a computer is really just a sequence of bytes (or bits). Just a matter on how you view it...
-
@Redman Looks like you should be able to at least put most of the case content into a template function, so your switch should look like
switch(ro) { case RoReceiver::ExampleClass: { createRemoteObject<ExampleClassReplica>(node, id, m_instanceTest); return; } // ...more cases
-
@Asperamanca That is correct.
What makes me wonder is that IqRegisterMetaType<ExampleClassReplica>();
which makes it usable with QMetaType. The way I understood QMetaType is that it provides reflection functionality. By calling QMetaType::create/convert I expected to get the correct type. But all it returns is a void* which I can not cast without explicitly knowing the type during compile time -
@Redman
I have to admit, I have never created objects in such a fashion myself.
But maybe the following works:QVariant v; QMetaType::convert(sourceTarget, targetType, v.data()); // Maybe also needed: v.convert(targetType);
If that works, and the contained type is a QObject type, you should be able to generically access properties, enumerations and suchlike.
-
@Asperamanca said in QMetaType casting to desired type:
@jeremy_k said in QMetaType casting to desired type:
@Asperamanca said in QMetaType casting to desired type:
@Redman
I guess you are missing this code:I saw that, and it surprised me that a sequence of bytes delivered over a network would successfully convert to a QObject.
Anything in a computer is really just a sequence of bytes (or bits). Just a matter on how you view it...
Structure within the data that includes pointers makes treating an object as just a sequence of bytes a little more complicated.
-
@Redman said in QMetaType casting to desired type:
@jeremy_k I'm talking QtRemoteObjects. I intentionally left that piece of information out because every time I mention them in this forum my posts never get answered.
That's an important detail. It sounds like a useful project. I personally have remained minimally interested due to the project's stated lack of interest in compatibility with non-QRO implementations. I'm not lucky enough to work in a distributed environment where all nodes run a compatible Qt application.
This switch statement is gonna get bigger and bigger aswell as be error prone.
Is there any way to make this piece of code dynamic?I was imagining:
template <class Type, class... Others> std::any convert(void *obj) { QMetaType fromType = QMetaType::fromType<NetworkClass>(); QMetaType toType = QMetaType::fromType<Type>(); std::any ret; if QMetaType::canConvert(fromType, toType) { QMetaType::convert(obj, fromType, &ret, toType); return ret; } else return convert<Others...>(obj); } template <> convert(void *obj) { return std::any(nullptr); } NetworkClass *obj = getObject(); std::any convertedObject = convert<Type1, Type2, Type3>(obj); if (std::any_cast<void *>(convertedObject) != nullptr) ...
- Not expected to compile as is
- Not runtime dynamic
- The user of the std::any will need to know what it wants to convert it to
I'm not sure this improves the situation.