Qt的元系统真的那么乏味吗?
Posted
技术标签:
【中文标题】Qt的元系统真的那么乏味吗?【英文标题】:Is Qt's meta system really that tedious? 【发布时间】:2016-11-08 09:29:59 【问题描述】:我想使用 Qt 的反射机制,因为 C++ 缺少这个特性。它似乎工作,但调用所有的宏和辅助函数是非常乏味的。例如,要将枚举注册为适当的元类型,我必须完成以下所有步骤:
-
在包含
Q_GADGET
宏的包装类中声明一个枚举。
在此之后使用Q_ENUM
宏注册枚举。
注册包含枚举的类:Q_DECLARE_METATYPE(MyClass)
调用qRegisterMetaType<..>()
获取包装类的类型和
对于每个声明的枚举。
现在我知道,如果不需要完整功能的一部分,可以省略一些步骤。但这不是我想要的,我需要在信号中使用枚举,并且我需要能够获取信号的元方法并查询它的参数类型。
但我还是忍不住想,一定有更好/更简单的方法来做到这一点。
【问题讨论】:
您具体需要做什么?也许确实你只需要所有这些的一个子集。 阅读问题 “我需要在信号中使用枚举,并且我需要能够获取信号的元方法并查询它的参数类型”并不能完全回答我的问题。你不需要Q_DECLARE_METATYPE
来上课。你不需要 qRegisterMetaType
来上课。这就是为什么我想知道您为什么要“全力以赴”并注册所有内容:)
是的,它可以在没有 qRegisterMetaType 的类的情况下工作,但是另一个用例可能无法工作。正如我所说,我希望能够充分使用它,而不必在声明类型时考虑所有可能的用例。
请记住,这涉及到很多遗留问题。特别是,Qt 大大早于 C++11。早期版本甚至不依赖模板,模板仍然是moc
的痛点。
【参考方案1】:
不幸的是,你不能少做这些。
Q_GADGET
(或 Q_OBJECT
,对于 QObject 子类)表示“为此类生成元对象信息”。
Q_ENUM
表示“为这个特定的枚举生成元枚举信息”。现在有人可能会争辩说,注册类中的所有(公共?)枚举也应该自动注册。但由于这是有成本的(二进制大小),而且我们使用 C++,我们不想为我们永远不会在元对象系统中使用的枚举付费,所以它是可选的。
Q_DECLARE_METATYPE
(如果您使用的是Q_ENUM
,则枚举本身不需要;在您的场景中一般不需要)使该类型能够在QVariant
s(Qt 的 C++98,RTTI-less 化身)中使用C++17 的std::any
)。你是否想要这个取决于类型。我会说所有“值类型”都应该有它,但同样,这会产生您可能不想支付的额外代码。此外,这实际上仅适用于“值类型”——此注册要求类型具有公共默认构造函数、公共复制构造函数、公共复制赋值、公共析构函数。如果你有一个没有这些的类,你就不能使用这个宏 => 你不能把它包装在 QVariant
中。
qRegisterMetaType
在运行时在表中注册上述构造函数/析构函数,使您能够拥有该类型的唯一 ID(如果您想在方法签名中识别类型,则需要),动态创建或销毁该类型的实例(需要,其中其他事情,实现排队连接:Qt 需要一种通用的方法来将信号的参数复制到要发送到目标线程的事件中,并在稍后销毁这些参数),使用 Q_PROPERTY 子系统。
根据您需要做什么,您需要所有这些的一个子集。
【讨论】:
感谢您的详细回答,我想知道是否有人尝试教代码生成器生成启用 Qt 元类型的代码,例如 Protocol Buffers?以上是关于Qt的元系统真的那么乏味吗?的主要内容,如果未能解决你的问题,请参考以下文章