Qt / C++: Is there a way to automatically register meta types?
为了获得 Qt 元类型系统的所有功能,我必须在应用程序初始化期间在运行时调用 qRegisterMetaType。具体来说,我需要注册:
-
我的每个 QObject 派生类的指针类型,即 qRegisterMetaType<MyClass *>(),以及
-
我使用 Q_DECLARE_METATYPE 声明为元类型的每种类型。
目前,我使用一个函数来执行此操作,该函数只为每个我手动维护和更新的函数调用 qRegisterMetaType。
然而,这对我来说相当不方便且容易出错。我经常健忘,忘记注册元类型不会产生任何编译错误,但是当我的代码尝试使用元类型系统并且因为我忘记注册其中一个而失败时,它会导致运行时错误。有时错误可能难以追踪。
那么有什么方法可以让我的所有 QObject 派生类和声明的元类型自动注册?
一些可能会影响解决方案的因素:
-
我需要注册的所有 QObject 派生类也都派生自我自己的单个基类,因此我可以使用它来实现每个其他类都将继承的功能。
-
如有必要,我愿意使用神秘的编译器技术!
- 这与未连接的信号/插槽相同。当 qRegisterMetaType 未声明但需要时,您将收到警告。在您发布应用程序之前,您需要检查您的日志/调试输出。我认为没有任何好方法可以自动执行此操作。
-
在调试版本中,我过滤 Qt 消息并在警告上设置断点。这样,如果 Qt 有我知道的警告。
-
检查这是否有助于模板类的 Q_DECLARE_METATYPE
-
这有点棘手。您需要创建自己的工厂,该工厂将注册将在运行时调用 qRegisterMetaType 的仿函数。这应该用于每个 exe/dll 实例。它可以用一些全局容器来完成,但是因为在 C 中没有定义初始化变量的顺序——它可能不是微不足道的。可能,我很快就会给你一个例子
我想不出一种自动声明元类型的方法,即不在类头中提供 Q_DECLARE_METATYPE 宏,但可以提供一个自动执行注册的宏(或多或少与元类型一起宣言)。此示例旨在声明和
只注册给定类的指针类型:
1 2 3 4 5 6 7 8 9 10 11
| #include <QMetaType>
#define METAID(CLASS) \\
Q_DECLARE_METATYPE(CLASS*) \\
static struct CLASS##Metaid \\
{ \\
CLASS##Metaid() \\
{ \\
qRegisterMetaType<CLASS*>(); \\
} \\
} _CLASS##metaid; |
上面的宏可以用来代替Q_DECLARE_METATYPE:
1 2 3 4 5 6
| class MyClass : public QObject
{
Q_OBJECT
};
METAID(MyClass) |
- 没有理由将基于 OObject 的类注册为元类型。它可能仅对指针有用。
-
另一个问题:复制 ctor 在 QObject 中是私有的 - 所以在子类中制作 ctor 没有任何意义。
-
是的@DmitrySazonov,但OP说他们必须注册QObject派生类......还是我误解了?
-
这对 OP 来说是个好问题。我能想象的只有一种情况——将指向基于 QObject 的实例的指针保存到 QVariant 中。据我了解 - OP 需要为 Q_DECLARE_METATYPE 的每次使用自动调用 qRegisterMetaType。
-
如果 CLASS 是不可复制的类型,这是非常错误的。我不确定它是否可以编译,或者如果没有 - 如果它链接。如果是这样,那就是等待发生的运行时错误。我也不确定在 QCoreApplication 实例化之前调用 qRegisterMetaType 是否有效。至少需要检查一下。最后,将在包含该标题的每个翻译单元中创建 CLASSMetaid 实例 - 毕竟它们是 static 。这有点浪费。
-
@KubaOber 不可复制的类不会编译, Q_DECLARE_METATYPE 会像往常一样失败。即使没有 QCoreApplication 实例,似乎元类型声明和注册也会成功。最后,是的:每个编译单元(包括 CLASS 标头)都会有一个一字节大小的 CLASSMetaid 实例。
-
@p-a-o-l-o 我只是想注册我所有类的指针类型。该线程中的其他人关于不注册非指针类类型是正确的。
-
@p-a-o-l-o 我没有考虑使用静态结构来做到这一点,我认为这对我来说是一个可行的解决方案。不过,在我接受它之前,您应该进行一些更改:a) 更改它以便它不注册非指针类类型,b) 将 CLASSMetaid 的实例更改为 CLASS ## Metaid 以便标记正确连接, 和 c) 将其更改为使用 qRegisterMetaType() 而不是 qMetaTypeId<T>() 因为即使它当前是等效的,也不能保证在未来的 Qt 版本中工作 - 更好地使用明确意味着的 API 函数注册元类型。
-
@p-a-o-l-o 那么带有命名空间的类呢?那是我前段时间的问题。