I\'ve been searching far and wide for an answer to this but to no avail. My lament is as follows:
I have a ClassA that roughly looks like this:
A few things:
The reason that registering ClassA* isn't working is because your call to construct() is constructing a pointer to a ClassA object, but not an actual object.
It is worthy of noting the following quote from the QMetaType documentation:
Any class or struct that has a public default constructor, a public copy constructor, and a public destructor can be registered.
Take a look at Qt's implementation of qMetaTypeConstructHelper:
template <typename T>
void *qMetaTypeConstructHelper(const T *t)
{
if (!t)
return new T();
return new T(*static_cast<const T*>(t));
}
and note their usage of the copy constructor. This being the case, you have two ways around the problem:
1) Provide a copy constructor (which you have done)
2) Provide a specialization of qMetaTypeConstructHelper that doesn't use the copy constructor:
template <>
void *qMetaTypeConstructHelper<ClassA>(const ClassA *)
{
return new ClassA();
}
Here's an update to Chris' solution #2 for Qt 5:
namespace QtMetaTypePrivate {
template <>
struct QMetaTypeFunctionHelper<ClassA, true> {
static void Delete(void *t)
{
delete static_cast<ClassA*>(t);
}
static void *Create(const void *t)
{
Q_UNUSED(t)
return new ClassA();
}
static void Destruct(void *t)
{
Q_UNUSED(t) // Silence MSVC that warns for POD types.
static_cast<ClassA*>(t)->~ClassA();
}
static void *Construct(void *where, const void *t)
{
Q_UNUSED(t)
return new (where) ClassA;
}
#ifndef QT_NO_DATASTREAM
static void Save(QDataStream &stream, const void *t)
{
stream << *static_cast<const ClassA*>(t);
}
static void Load(QDataStream &stream, void *t)
{
stream >> *static_cast<ClassA*>(t);
}
#endif // QT_NO_DATASTREAM
};
}
If your ClassA doesn't implement operator<< and operator>> helpers for QDataStream, comment out the bodies of Save and Load or you'll still have a compiler error.
If you want to create instances of QObject classes by name, you can use QMetaObject instead of QMetaType.
First, you have to declare your constructor as invokable:
class ClassA : public QObject {
Q_OBJECT
public:
Q_INVOKABLE ClassA() { mName = "lol"; }
~ClassA();
void showName() { std::cout << mName << std::endl; }
std::string mName;
};
Then you have to create your own registration system for the classes you want to instantiate, and populate it manually:
int main(int argc, char *argv[])
{
// Register your QObject derived classes
QList<const QMetaObject*> metaObjectList;
metaObjectList << &ClassA::staticMetaObject;
// Index the classes/metaobject by their names
QMap<QString, const QMetaObject*> metaObjectLookup;
foreach(const QMetaObject *mo, metaObjectList) {
metaObjectLookup.insert(mo->className(), mo);
}
And finally you'll be able instantiate by name any registered class:
const QMetaObject * myMetaObject = metaObjectLookup.value("ClassA", 0);
if(!myMetaObject)
{
// The class doesn't exist
return 1;
}
ClassA *myObject =
static_cast<ClassA*>(myMetaObject->newInstance());
if(!myObject)
{
// Couldn't create an instance (constructor not declared Q_INVOKABLE ?)
return 1;
}
myObject->showName();
return 0;
}