在Qt中注册元类型的模式

hyd*_*yde 8 c++ qt

介绍

我有一个库,它注册了一堆元类型,由这段代码说明:


abstractfoobase.h

namespace foo {
    enum FooState { OK, MAYBE };
    class AbstractFooBase : public QObject {...};
}

Q_DECLARE_METATYPE(foo::FooState)
Run Code Online (Sandbox Code Playgroud)

还有一个相应的abstractfoobase.cpp,内容取决于在基类中实现的内容.


foousingclass.h:

namespace foo {

    class FooUsingClass : public AbstractFooBase {...};
}
Run Code Online (Sandbox Code Playgroud)

同样有相应的foousingclass.cpp,它有方法实现等.


现在,它Q_DECLARE_METATYPE启用了Qt模板类的类型QVariant.要启用使用排队信号中的类型等,还需要进行相应的调用:

qRegisterMetaType<foo::FooState>();
Run Code Online (Sandbox Code Playgroud)

qRegisterMetaType拨打电话的好地方是什么?我显然不希望从应用程序代码中进行任何明显的初始化调用.注册必须在做完之后发生foo::FooUsingClass *f = new foo::FooUsingClass();.

在Java中,我将这种代码放在静态初始化块中.我也可以在C++中看到几种方法来实现这一点,但是它们中没有一个看起来特别好看.例如,简单地将这些放入AbstractFooBase构造函数将导致每次创建子类实例时调用注册,这可能是不希望的开销.所以那些做过这个的人,你在哪里qRegisterMetaType打电话?

Arc*_*hie 6

我可以想象如下:

在abstractfoobase.cpp中:

namespace foo {

/// Initializer
class FooStateInit {
public:
    FooStateInit() {
        qRegisterMetaType<foo::FooState>();
    }
};
static FooStateInit fooStateInit;

} // namespace foo
Run Code Online (Sandbox Code Playgroud)


kla*_*ndl 5

我最近发现了一个简单的解决方案,它也可以与静态库一起使用。

它利用了qMetaTypeId<>()整个Qt元类型系统中使用的事实。因此,通过显式的模板实例化,我们可以强制链接到abstractfoobase.cpp(否则,链接程序可能会决定是否不存在引用的符号),并确保在程序启动时静态注册该类型:

abstractfoobase.h

#include <QMetaType>

namespace foo {
    enum FooState { OK, MAYBE };
}

Q_DECLARE_METATYPE(foo::FooState)

extern template int qMetaTypeId<foo::FooState>();
Run Code Online (Sandbox Code Playgroud)

abstractfoobase.cpp

static const int kFooStateMetaTypeId = qRegisterMetaType<foo::FooState>();

template int qMetaTypeId<foo::FooState>();
Run Code Online (Sandbox Code Playgroud)