Qt MetaTypeInterface
- Qt中的Meta Type 包含两种类型,每个类型都以一个整型ID来表示, 内建类型和用户自定义类型(自定义类型对应的整型ID 从65536 即 QMetaType::User 开始):
1)内建类型:
corelib\kernel\qmetatype.h
// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
#define QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F)\
F(Bool, 1, bool) \
F(Int, 2, int) \
F(UInt, 3, uint) \
F(LongLong, 4, qlonglong) \
F(ULongLong, 5, qulonglong) \
F(Double, 6, double) \
F(Long, 32, long) \
F(Short, 33, short) \
F(Char, 34, char) \
F(Char16, 56, char16_t) \
F(Char32, 57, char32_t) \
F(ULong, 35, ulong) \
F(UShort, 36, ushort) \
F(UChar, 37, uchar) \
F(Float, 38, float) \
F(SChar, 40, signed char) \
F(Nullptr, 51, std::nullptr_t) \
F(QCborSimpleType, 52, QCborSimpleType) \
#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \
QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F) \
F(Void, 43, void) \
#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F) \
F(VoidStar, 31, void*) \
#if QT_CONFIG(easingcurve)
#define QT_FOR_EACH_STATIC_EASINGCURVE(F)\
F(QEasingCurve, 29, QEasingCurve)
#else
#define QT_FOR_EACH_STATIC_EASINGCURVE(F)
#endif
#if QT_CONFIG(itemmodel)
#define QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)\
F(QModelIndex, 42, QModelIndex) \
F(QPersistentModelIndex, 50, QPersistentModelIndex)
#else
#define QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
#endif
#if QT_CONFIG(regularexpression)
# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
F(QRegularExpression, 44, QRegularExpression)
#else
# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F)
#endif
#define QT_FOR_EACH_STATIC_CORE_CLASS(F)\
F(QChar, 7, QChar) \
F(QString, 10, QString) \
F(QByteArray, 12, QByteArray) \
F(QBitArray, 13, QBitArray) \
F(QDate, 14, QDate) \
F(QTime, 15, QTime) \
F(QDateTime, 16, QDateTime) \
F(QUrl, 17, QUrl) \
F(QLocale, 18, QLocale) \
F(QRect, 19, QRect) \
F(QRectF, 20, QRectF) \
F(QSize, 21, QSize) \
F(QSizeF, 22, QSizeF) \
F(QLine, 23, QLine) \
F(QLineF, 24, QLineF) \
F(QPoint, 25, QPoint) \
F(QPointF, 26, QPointF) \
QT_FOR_EACH_STATIC_EASINGCURVE(F) \
F(QUuid, 30, QUuid) \
F(QVariant, 41, QVariant) \
QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
F(QJsonValue, 45, QJsonValue) \
F(QJsonObject, 46, QJsonObject) \
F(QJsonArray, 47, QJsonArray) \
F(QJsonDocument, 48, QJsonDocument) \
F(QCborValue, 53, QCborValue) \
F(QCborArray, 54, QCborArray) \
F(QCborMap, 55, QCborMap) \
F(Float16, 63, qfloat16) \
QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
#define QT_FOR_EACH_STATIC_CORE_POINTER(F)\
F(QObjectStar, 39, QObject*)
#define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
F(QVariantMap, 8, QVariantMap) \
F(QVariantList, 9, QVariantList) \
F(QVariantHash, 28, QVariantHash) \
F(QVariantPair, 58, QVariantPair) \
F(QByteArrayList, 49, QByteArrayList) \
F(QStringList, 11, QStringList) \
#if QT_CONFIG(shortcut)
#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)\
F(QKeySequence, 0x100b, QKeySequence)
#else
#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)
#endif
#define QT_FOR_EACH_STATIC_GUI_CLASS(F)\
F(QFont, 0x1000, QFont) \
F(QPixmap, 0x1001, QPixmap) \
F(QBrush, 0x1002, QBrush) \
F(QColor, 0x1003, QColor) \
F(QPalette, 0x1004, QPalette) \
F(QIcon, 0x1005, QIcon) \
F(QImage, 0x1006, QImage) \
F(QPolygon, 0x1007, QPolygon) \
F(QRegion, 0x1008, QRegion) \
F(QBitmap, 0x1009, QBitmap) \
F(QCursor, 0x100a, QCursor) \
QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F) \
F(QPen, 0x100c, QPen) \
F(QTextLength, 0x100d, QTextLength) \
F(QTextFormat, 0x100e, QTextFormat) \
F(QTransform, 0x1010, QTransform) \
F(QMatrix4x4, 0x1011, QMatrix4x4) \
F(QVector2D, 0x1012, QVector2D) \
F(QVector3D, 0x1013, QVector3D) \
F(QVector4D, 0x1014, QVector4D) \
F(QQuaternion, 0x1015, QQuaternion) \
F(QPolygonF, 0x1016, QPolygonF) \
F(QColorSpace, 0x1017, QColorSpace) \
#define QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\
F(QSizePolicy, 0x2000, QSizePolicy) \
// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, AliasingType, "RealType")
#define QT_FOR_EACH_STATIC_ALIAS_TYPE(F)\
F(ULong, -1, ulong, "unsigned long") \
F(UInt, -1, uint, "unsigned int") \
F(UShort, -1, ushort, "unsigned short") \
F(UChar, -1, uchar, "unsigned char") \
F(LongLong, -1, qlonglong, "long long") \
F(ULongLong, -1, qulonglong, "unsigned long long") \
F(SChar, -1, signed char, "qint8") \
F(UChar, -1, uchar, "quint8") \
F(Short, -1, short, "qint16") \
F(UShort, -1, ushort, "quint16") \
F(Int, -1, int, "qint32") \
F(UInt, -1, uint, "quint32") \
F(LongLong, -1, qlonglong, "qint64") \
F(ULongLong, -1, qulonglong, "quint64") \
F(QVariantList, -1, QVariantList, "QList<QVariant>") \
F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
F(QVariantPair, -1, QVariantPair, "QPair<QVariant,QVariant>") \
F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
F(QStringList, -1, QStringList, "QList<QString>") \
#define QT_FOR_EACH_STATIC_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
QT_FOR_EACH_STATIC_CORE_CLASS(F)\
QT_FOR_EACH_STATIC_CORE_POINTER(F)\
QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
QT_FOR_EACH_STATIC_GUI_CLASS(F)\
QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\
#define QT_DEFINE_METATYPE_ID(TypeName, Id, Name) \
TypeName = Id,
#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \
F(QList) \
F(QQueue) \
F(QStack) \
F(QSet) \
/*end*/
#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(F) \
F(QHash, class) \
F(QMap, class)
#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(F) \
F(QSharedPointer) \
F(QWeakPointer) \
F(QPointer)
class Q_CORE_EXPORT QMetaType {
public:
#ifndef Q_QDOC
// The code that actually gets compiled.
enum Type {
// these are merged with QVariant
QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
FirstCoreType = Bool,
LastCoreType = Float16,
FirstGuiType = QFont,
LastGuiType = QColorSpace,
FirstWidgetsType = QSizePolicy,
LastWidgetsType = QSizePolicy,
HighestInternalId = LastWidgetsType,
QReal = sizeof(qreal) == sizeof(double) ? Double : Float,
UnknownType = 0,
User = 65536
};
#else
// If we are using QDoc it fakes the Type enum looks like this.
enum Type {
UnknownType = 0, Bool = 1, Int = 2, UInt = 3, LongLong = 4, ULongLong = 5,
Double = 6, Long = 32, Short = 33, Char = 34, ULong = 35, UShort = 36,
UChar = 37, Float = 38,
VoidStar = 31,
QChar = 7, QString = 10, QStringList = 11, QByteArray = 12,
QBitArray = 13, QDate = 14, QTime = 15, QDateTime = 16, QUrl = 17,
QLocale = 18, QRect = 19, QRectF = 20, QSize = 21, QSizeF = 22,
QLine = 23, QLineF = 24, QPoint = 25, QPointF = 26,
QEasingCurve = 29, QUuid = 30, QVariant = 41, QModelIndex = 42,
QPersistentModelIndex = 50, QRegularExpression = 44,
QJsonValue = 45, QJsonObject = 46, QJsonArray = 47, QJsonDocument = 48,
QByteArrayList = 49, QObjectStar = 39, SChar = 40,
Void = 43,
Nullptr = 51,
QVariantMap = 8, QVariantList = 9, QVariantHash = 28, QVariantPair = 58,
QCborSimpleType = 52, QCborValue = 53, QCborArray = 54, QCborMap = 55,
Char16 = 56, Char32 = 57,
Int128 = 59, UInt128 = 60, Float128 = 61, BFloat16 = 62, Float16 = 63,
// Gui types
QFont = 0x1000, QPixmap = 0x1001, QBrush = 0x1002, QColor = 0x1003, QPalette = 0x1004,
QIcon = 0x1005, QImage = 0x1006, QPolygon = 0x1007, QRegion = 0x1008, QBitmap = 0x1009,
QCursor = 0x100a, QKeySequence = 0x100b, QPen = 0x100c, QTextLength = 0x100d, QTextFormat = 0x100e,
QTransform = 0x1010, QMatrix4x4 = 0x1011, QVector2D = 0x1012,
QVector3D = 0x1013, QVector4D = 0x1014, QQuaternion = 0x1015, QPolygonF = 0x1016, QColorSpace = 0x1017,
// Widget types
QSizePolicy = 0x2000,
// Start-point for client-code types:
User = 65536
};
2)自定义类型,需要向customRegistry中注册用户自定义类型信息:
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
QT_WARNING_PUSH \
QT_WARNING_DISABLE_CLANG("-Wunevaluated-expression") \
namespace { struct Q_QGS_ ## NAME { \
typedef TYPE QGS_Type; \
static void innerFunction(void *pointer) \
noexcept(noexcept(std::remove_cv_t<QGS_Type> ARGS)) \
{ \
new (pointer) QGS_Type ARGS; \
} \
}; } \
Q_CONSTINIT static QGlobalStatic<QtGlobalStatic::Holder<Q_QGS_ ## NAME>> NAME; \
QT_WARNING_POP
/**/
#define Q_GLOBAL_STATIC(TYPE, NAME, ...) \
Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, (__VA_ARGS__))
Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry)
宏定义替换后会得到一个静态全局变量 customTypeRegistry的声明,类型为QGlobalStatic<QtGlobalStatic::Holder<Q_QGS_customTypeRegistry >>,
替换后的代码如下:
namespace
{
struct Q_QGS_customTypeRegistry
{
typedef TYPE QMetaTypeCustomRegistry;
static void innerFunction(void *pointer) noexcept(noexcept(QMetaTypeCustomRegistry ()))
{
new (pointer) QMetaTypeCustomRegistry() ;
}
};
}
Q_CONSTINIT static QGlobalStatic<QtGlobalStatic::Holder<Q_QGS_customTypeRegistry >> customTypeRegistry;
在QMetaTypeCustomRegistry类中提供了注册自定义类型的接口:
struct QMetaTypeCustomRegistry
{
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
QMetaTypeCustomRegistry()
{
/* qfloat16 was neither a builtin, nor unconditionally registered
in QtCore in Qt <= 6.2.
Inserting it as an alias ensures that a QMetaType::id call
will get the correct built-in type-id (the interface pointers
might still not match, but we already deal with that case.
*/
aliases.insert("qfloat16", QtPrivate::qMetaTypeInterfaceForType<qfloat16>());
}
#endif
QReadWriteLock lock;
QList<const QtPrivate::QMetaTypeInterface *> registry;
QHash<QByteArray, const QtPrivate::QMetaTypeInterface *> aliases;
// index of first empty (unregistered) type in registry, if any.
int firstEmpty = 0;
int registerCustomType(const QtPrivate::QMetaTypeInterface *cti)
{
// we got here because cti->typeId is 0, so this is a custom meta type
// (not read-only)
auto ti = const_cast<QtPrivate::QMetaTypeInterface *>(cti);
{
QWriteLocker l(&lock);
if (int id = ti->typeId.loadRelaxed())
return id;
QByteArray name =
#ifndef QT_NO_QOBJECT
QMetaObject::normalizedType
#endif
(ti->name);
if (auto ti2 = aliases.value(name)) {
const auto id = ti2->typeId.loadRelaxed();
ti->typeId.storeRelaxed(id);
return id;
}
aliases[name] = ti;
int size = registry.size();
while (firstEmpty < size && registry[firstEmpty])
++firstEmpty;
if (firstEmpty < size) {
registry[firstEmpty] = ti;
++firstEmpty;
} else {
registry.append(ti);
firstEmpty = registry.size();
}
ti->typeId.storeRelaxed(firstEmpty + QMetaType::User);
}
if (ti->legacyRegisterOp)
ti->legacyRegisterOp();
return ti->typeId.loadRelaxed();
};
.........
.........
.........
};
- 在信号槽机制中,如果使用QueuedConnection连接类型,当信号和槽中使用了自定义数据类型传递参数时需要首先注册自定义数据类型,如:
qRegisterMetaType("Add");
至于为何需要注册自定义类型,个人理解理由如下:
在QueuedConnection 连接方式下 信号触发时 并非 对 槽函数的同步调用,而是封装一个QMetaCallEvent 以post方式放到receiver对象所
附属的线程对应的连接队列中等待后续EventLoop循环中对取对应的Event处理。信号函数调用结束后 栈帧已经销毁,无法在后续的
Eventloop 循环中从栈中拿到对应的参数数据。
因此,比较自然的方法就是将要传递的函数参数保存在 堆上,这样不会随信号函数调用的结束而丢失要传递的参数。保存在堆上的参数内存地址
存放在上述的MetaCallEvent对象中,这样在后续循环中执行槽函数时可以获取到需要的函数参数数据。
又由于Qt 针对信号槽机制中传递参数为了更通用,因此创建链接的内部框架代码中 参数都是以 void* 类型来声明的。
因此在传递给Qt框架源码时都将 用户的数据强制转换为了 void*。例如如下代码所示:
由于传递进去的是void* 类型的参数,因此要将 该参数 拷贝到 堆上保存,这时就需要知道要拷贝多少个字节。为了需要这个字节大小信息 ,
因此需要有个地方记录,而记录字节大小的信息就以QMetaType的形式存放在customTypeRegistry中。Qt框架中记录了信号和槽函数中参数个数,
参数类型信息。在使用自定义数据类型前先注册,注册时会在注册表中给这个新的用户自定义类型信息分配一个 整型ID,同时会根据该数据类型是否是
non-trival class,并为non-trival class type声明和定义copyCtr,moveCtr,dtor等
拷贝构造,移动构造,析构函数信息(对于non-trival class 类型如果通过memcpy来复制一个类对象,可能会引发问题。该类中提供的自定义构造函数可能
通过new或者malloc在堆上分配了内存并将首地址保存在 对象的某个指针变量中,memcpy只会简单复制指针的值而不会重新分配内存,当源对象销毁时可能
在用户自定义的析构函数中 已经delete 或者 free了堆上分配的那块儿空间,但是通过memcpy拷贝出来的对象数据在强制转换为对应的类对象 使用完毕后
对象销毁时 同样会执行析构函数,因此再次针对 堆上那块儿空间进行delete或者free操作,程序会因此crash)。如下代码:
template<typename T>
struct QMetaTypeInterfaceWrapper
{
// if the type ID for T is known at compile-time, then we can declare
// the QMetaTypeInterface object const; otherwise, we declare it as
// non-const and the .typeId is updated by QMetaType::idHelper().
static constexpr bool IsConstMetaTypeInterface = !!BuiltinMetaType<T>::value;
using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>;
static inline InterfaceType metaType = {
/*.revision=*/ QMetaTypeInterface::CurrentRevision,
/*.alignment=*/ alignof(T),
/*.size=*/ sizeof(T),
/*.flags=*/ QMetaTypeForType<T>::Flags,
/*.typeId=*/ BuiltinMetaType<T>::value,
/*.metaObjectFn=*/ MetaObjectForType<T>::metaObjectFunction,
/*.name=*/ QMetaTypeForType<T>::getName(),
/*.defaultCtr=*/ QMetaTypeForType<T>::getDefaultCtr(),
/*.copyCtr=*/ QMetaTypeForType<T>::getCopyCtr(),
/*.moveCtr=*/ QMetaTypeForType<T>::getMoveCtr(),
/*.dtor=*/ QMetaTypeForType<T>::getDtor(),
/*.equals=*/ QEqualityOperatorForType<T>::equals,
/*.lessThan=*/ QLessThanOperatorForType<T>::lessThan,
/*.debugStream=*/ QDebugStreamOperatorForType<T>::debugStream,
/*.dataStreamOut=*/ QDataStreamOperatorForType<T>::dataStreamOut,
/*.dataStreamIn=*/ QDataStreamOperatorForType<T>::dataStreamIn,
/*.legacyRegisterOp=*/ QMetaTypeForType<T>::getLegacyRegister()
};
};
template<typename S>
class QMetaTypeForType
{
public:
static constexpr decltype(typenameHelper<S>()) name = typenameHelper<S>();
static constexpr unsigned Flags = QMetaTypeTypeFlags<S>::Flags;
static constexpr QMetaTypeInterface::DefaultCtrFn getDefaultCtr()
{
if constexpr (std::is_default_constructible_v<S> && !QTypeInfo<S>::isValueInitializationBitwiseZero) {
return [](const QMetaTypeInterface *, void *addr) { new (addr) S(); };
} else {
return nullptr;
}
}
static constexpr QMetaTypeInterface::CopyCtrFn getCopyCtr()
{
if constexpr (std::is_copy_constructible_v<S> && !std::is_trivially_copy_constructible_v<S>) {
return [](const QMetaTypeInterface *, void *addr, const void *other) {
new (addr) S(*reinterpret_cast<const S *>(other));
};
} else {
return nullptr;
}
}
static constexpr QMetaTypeInterface::MoveCtrFn getMoveCtr()
{
if constexpr (std::is_move_constructible_v<S> && !std::is_trivially_move_constructible_v<S>) {
return [](const QMetaTypeInterface *, void *addr, void *other) {
new (addr) S(std::move(*reinterpret_cast<S *>(other)));
};
} else {
return nullptr;
}
}
static constexpr QMetaTypeInterface::DtorFn getDtor()
{
if constexpr (std::is_destructible_v<S> && !std::is_trivially_destructible_v<S>)
return [](const QMetaTypeInterface *, void *addr) {
reinterpret_cast<S *>(addr)->~S();
};
else
return nullptr;
}
}
在QCoreApplicationPrivate::sendPostedEvents中取出PostEvent包装着的QMetaCallEvent后
先将其初始化给 QScopedPointer event_deleter(e),这样可以在sendPostedEvents函数返回后
通过栈销毁event_deleter时调用其Cleanup 的cleanup来释放资源,这里采用的是QScopedPointerDeleter,
其cleanup行为就是delete pointer,引起会调用QMetaCallEvent的析构函数,进而调用其中存储的参数的destroy函数,
destroy函数中调用destruct,其中调用了析构函数,然后调用了QMetaTypeDeleter仿函数对象,其实是调用全局的
operator delete ,到此为止会将 queued_activate函数中 QMetaCallEvent为保存信号函数参数
在堆上申请的内存释放完成了。
QScopedPointer<QEvent> event_deleter(e); // will delete the event (with the mutex unlocked)
/*!
template <typename T>
struct QScopedPointerDeleter
{
static inline void cleanup(T *pointer) noexcept
{
// Enforce a complete type.
// If you get a compile error here, read the section on forward declared
// classes in the QScopedPointer documentation.
typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ];
(void) sizeof(IsIncompleteType);
delete pointer;
}
void operator()(T *pointer) const noexcept
{
cleanup(pointer);
}
};
template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
class QScopedPointer
{
public:
Q_NODISCARD_CTOR
explicit QScopedPointer(T *p = nullptr) noexcept : d(p)
{
}
inline ~QScopedPointer()
{
T *oldD = this->d;
Cleanup::cleanup(oldD);
}
......
};
\internal
*/
QMetaCallEvent::~QMetaCallEvent()
{
if (d.nargs_) {
QMetaType *t = types();
for (int i = 0; i < d.nargs_; ++i) {
if (t[i].isValid() && d.args_[i])
t[i].destroy(d.args_[i]);
}
if (reinterpret_cast<void *>(d.args_) != reinterpret_cast<void *>(prealloc_))
free(d.args_);
}
}
/*!
\fn void QMetaType::destroy(void *data) const
\since 5.0
Destroys the \a data, assuming it is of the type that this
QMetaType instance was created for.
\sa QMetaType::create()
*/
void QMetaType::destroy(void *data) const
{
if (data && isDestructible()) {
QtMetaTypePrivate::destruct(d_ptr, data);
QMetaTypeDeleter{d_ptr}(data);
}
}
inline void destruct(const QtPrivate::QMetaTypeInterface *iface, void *where)
{
Q_ASSERT(isDestructible(iface));
if (iface->dtor)
iface->dtor(iface, where);
}
struct QMetaTypeDeleter
{
const QtPrivate::QMetaTypeInterface *iface;
void operator()(void *data)
{
if (iface->alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
operator delete(data, std::align_val_t(iface->alignment));
} else {
operator delete(data);
}
}
};
- 根据类型ID 查找返回对应的QMetaTypeInterface信息
static const QtPrivate::QMetaTypeInterface *interfaceForType(int typeId)
{
const QtPrivate::QMetaTypeInterface *iface = interfaceForTypeNoWarning(typeId);
if (!iface && typeId != QMetaType::UnknownType)
qWarning("Trying to construct an instance of an invalid type, type id: %i", typeId);
return iface;
}
static const QtPrivate::QMetaTypeInterface *interfaceForTypeNoWarning(int typeId)
{
const QtPrivate::QMetaTypeInterface *iface = nullptr;
if (typeId >= QMetaType::User) { //如果typeId >= 65536 属于自定义数据类型,因此需要从注册表里面查找
if (customTypeRegistry.exists())
iface = customTypeRegistry->getCustomType(typeId);
} else { //typeId < 65536 属于QT 自建类型信息,从对应的moduleHelper中查找
if (auto moduleHelper = qModuleHelperForType(typeId))
iface = moduleHelper->interfaceForType(typeId);
}
return iface;
}
static const struct : QMetaTypeModuleHelper
{
template<typename T, typename LiteralWrapper =
std::conditional_t<std::is_same_v<T, QString>, QLatin1StringView, const char *>>
static inline bool convertToBool(const T &source)
{
T str = source.toLower();
return !(str.isEmpty() || str == LiteralWrapper("0") || str == LiteralWrapper("false"));
}
const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override {
switch (type) {
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_CONVERT_ID_TO_TYPE)
QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_CONVERT_ID_TO_TYPE)
QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE)
QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_CONVERT_ID_TO_TYPE)
QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_CONVERT_ID_TO_TYPE)
default:
return nullptr;
}
}
..........................
..........................
..........................
} metatypeHelper = {};
Q_CONSTINIT Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper = nullptr;
Q_CONSTINIT Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeWidgetsHelper = nullptr;
static const QMetaTypeModuleHelper *qModuleHelperForType(int type)
{
if (type <= QMetaType::LastCoreType)
return &metatypeHelper;
if (type >= QMetaType::FirstGuiType && type <= QMetaType::LastGuiType)
return qMetaTypeGuiHelper;
else if (type >= QMetaType::FirstWidgetsType && type <= QMetaType::LastWidgetsType)
return qMetaTypeWidgetsHelper;
return nullptr;
}
===========================================================
C++ trivial和non-trivial构造函数及POD类型
今天看书看到侯捷的《STL源码剖析》里提到trivial和non-trivial及POD类型,查了些资料理解了一下。
trivial意思是无意义,这个trivial和non-trivial是对类的四种函数来说的:
构造函数(ctor)
复制构造函数(copy)
赋值函数(assignment)
析构函数(dtor)
如果至少满足下面3条里的一条:
显式(explict)定义了这四种函数。
类里有非静态非POD的数据成员。
有基类。
那么上面的四种函数是non-trivial函数,比如叫non-trivial ctor、non-trivial copy…,也就是说有意义的函数,里面有一下必要的操作,
比如类成员的初始化,释放内存等。
那个POD意思是Plain Old Data,也就是C++的内建类型或传统的C结构体类型。POD类型必然有trivial ctor/dtor/copy/assignment四种函数。
//整个T是POD类型
class T
{
//没有显式定义ctor/dtor/copy/assignemt所以都是trivial
int a; //POD类型
};
//整个T1是非POD类型
class T1
{
T1() //显式定义了构造函数,所以是non-trivial ctor
{}
//没有显式定义ctor/dtor/copy/assignemt所以都是trivial
int a;//POD类型
std::string b; //非POD类型
};
那这有什么用处呢?
如果这个类都是trivial ctor/dtor/copy/assignment函数,我们对这个类进行构造、析构、拷贝和赋值时可以采用最有效率的方法,
不调用无所事事正真的那些ctor/dtor等,而直接采用内存操作如malloc()、memcpy()等提高性能,这也是SGI STL内部干的事情。
比如STL的copy算法最基本的想法是这样的:
// 非POD重载指针数值
template <class T> void copy(T* source, T* destination, int n, __false_type)
{
// 省略异常处理
for (; n > 0; n--,source++,destination++)
{
// 调用source的复制构造函数
constructor(source, *destination);
}
}
// POD重载指针数值
template <class T> void copy(T* source, T* destination, int n, __false_type)
{
// 省略异常处理
memmove(source, destination, n);
}
当然实际的copy比这个复杂多了,有非常多的特化等,这个只是其中一方面而已。