Qt 的元系统真的那么乏味吗?

Is Qt's meta system really that tedious?

我想使用 Qt 的反射机制,因为 C++ 缺少此功能。它似乎可以工作,但是调用所有宏和辅助函数非常繁琐。例如,要将枚举注册为适当的元类型,我必须完成以下所有步骤:

  1. 在包含 Q_GADGET 宏的包装器 class 中声明一个枚举。
  2. 之后使用 Q_ENUM 宏注册枚举。
  3. 注册包含枚举的 class:Q_DECLARE_METATYPE(MyClass)
  4. 调用 qRegisterMetaType<..>() 包装类型 class 和 对于每个声明的枚举。

现在我知道如果不需要部分完整功能,可以省略一些步骤。但这不是我要找的,我需要在信号中使用枚举,我需要能够获取信号的元方法并查询它的参数类型。

但我还是忍不住想一定有 better/simpler 方法可以做到这一点。

不幸的是,你不能做不到。

  • Q_GADGET(或 Q_OBJECT,对于 QObject subclasses)表示 "generate meta-object information for this class".
  • Q_ENUM 表示 "generate meta-enum information for this particular enum"。现在有人可能会争辩说,注册的 class 中的所有 (public?) 枚举也应该自动注册。但由于这是有成本的(二进制大小),而且我们使用 C++,我们不想为我们永远不会在元对象系统中使用的枚举付费,所以它是选择加入的。
  • Q_DECLARE_METATYPE(如果您使用 Q_ENUM,则枚举本身不需要;在您的场景中,通常不需要)使类型可以在 QVariants 中使用(Qt 的 C++98,C++17 的无 RTTI 化身 std::any)。你是否想要这个取决于类型。我会说所有 "value types" 都应该有它,但同样,这会生成您可能不想支付的额外代码。此外,这仅适用于 "value types"——此注册要求类型具有 public 默认构造函数、public 复制构造函数、public 复制赋值、public析构函数。如果你有一个 class 而没有这些,你不能使用这个宏 => 你不能把它包装在 QVariant.
  • qRegisterMetaType 在运行时将上述 constructors/destructors 注册到 table 中,使您能够拥有该类型的唯一 ID(如果您想在方法签名中识别类型,则需要) ,动态创建或销毁该类型的实例(除其他事项外,需要实现排队连接:Qt 需要一种通用方法将信号的参数复制到要发送到目标线程的事件中,并稍后销毁此类参数),使用Q_PROPERTY 子系统。

根据您具体需要做什么,您需要所有这些的一部分。