Qt 的元系统真的那么乏味吗?
Is Qt's meta system really that tedious?
我想使用 Qt 的反射机制,因为 C++ 缺少此功能。它似乎可以工作,但是调用所有宏和辅助函数非常繁琐。例如,要将枚举注册为适当的元类型,我必须完成以下所有步骤:
- 在包含
Q_GADGET
宏的包装器 class 中声明一个枚举。
- 之后使用
Q_ENUM
宏注册枚举。
- 注册包含枚举的 class:
Q_DECLARE_METATYPE(MyClass)
- 调用
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
,则枚举本身不需要;在您的场景中,通常不需要)使类型可以在 QVariant
s 中使用(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 子系统。
根据您具体需要做什么,您需要所有这些的一部分。
我想使用 Qt 的反射机制,因为 C++ 缺少此功能。它似乎可以工作,但是调用所有宏和辅助函数非常繁琐。例如,要将枚举注册为适当的元类型,我必须完成以下所有步骤:
- 在包含
Q_GADGET
宏的包装器 class 中声明一个枚举。 - 之后使用
Q_ENUM
宏注册枚举。 - 注册包含枚举的 class:
Q_DECLARE_METATYPE(MyClass)
- 调用
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
,则枚举本身不需要;在您的场景中,通常不需要)使类型可以在QVariant
s 中使用(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 子系统。
根据您具体需要做什么,您需要所有这些的一部分。