Qt中,QT_FOR_EACH_STATIC_TYPE是一个很关键的宏,在很多地方都有用到,QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE) 将qt中的类型
下面的代码将QT_FOR_EACH_STATIC_TYPE、QT_FOR_EACH_STATIC_HACKS_TYPE、QT_FOR_EACH_STATIC_ALIAS_TYPE中标注的类型信息初始化到types这个全局静态数组变量中
//QtInstallDir\Src\qtbase\src\corelib\kernel\qmetatype.cpp
.......
#define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \
{ #RealName, sizeof(#RealName) - 1, MetaTypeId },
#define QT_ADD_STATIC_METATYPE_ALIASES_ITER(MetaTypeName, MetaTypeId, AliasingName, RealNameStr) \
{ RealNameStr, sizeof(RealNameStr) - 1, QMetaType::MetaTypeName },
#define QT_ADD_STATIC_METATYPE_HACKS_ITER(MetaTypeName, TypeId, Name) \
QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeName, Name)
static const struct { const char * typeName; int typeNameLength; int type; } types[] = {
QT_FOR_EACH_STATIC_TYPE(QT_ADD_STATIC_METATYPE)
QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER)
QT_FOR_EACH_STATIC_HACKS_TYPE(QT_ADD_STATIC_METATYPE_HACKS_ITER)
{0, 0, QMetaType::UnknownType}
};
.......
下面代码将QT_FOR_EACH_STATIC_TYPE中标注的类型信息初始化到metaTypeNames对象中metaTypeNames与上面的types变量功能是有重合的。但是types中记录有重复,比如ulong 与unsigned long是重复的,在metaTypeNames中只有ulong项。
namespace {
// All type names in one long string.
constexpr char metaTypeStrings[] = QT_FOR_EACH_STATIC_TYPE(STRINGIFY_TYPE_NAME);
// The sizes of the strings in the metaTypeStrings string (including terminating null)
constexpr short metaTypeNameSizes[] = {
QT_FOR_EACH_STATIC_TYPE(CALCULATE_TYPE_LEN)
};
// The type IDs, in the order of the metaTypeStrings data
constexpr short metaTypeIds[] = {
QT_FOR_EACH_STATIC_TYPE(MAP_TYPE_ID_TO_IDX)
};
constexpr int MetaTypeNameCount = sizeof(metaTypeNameSizes) / sizeof(metaTypeNameSizes[0]);
template <typename IntegerSequence> struct MetaTypeOffsets;
template <int... TypeIds> struct MetaTypeOffsets<QtPrivate::IndexesList<TypeIds...>>
{
// This would have been a lot easier if the meta types that the macro
// QT_FOR_EACH_STATIC_TYPE declared were in sorted, ascending order, but
// they're not (i.e., the first one declared is QMetaType::Void == 43,
// followed by QMetaType::Bool == 1)... As a consequence, we need to use
// the C++11 constexpr function calculateOffsetForTypeId below in order to
// create the offset array.
static constexpr int findTypeId(int typeId, int i = 0)
{
return i >= MetaTypeNameCount ? -1 :
metaTypeIds[i] == typeId ? i : findTypeId(typeId, i + 1);
}
static constexpr short calculateOffsetForIdx(int i)
{
return i < 0 ? -1 :
i == 0 ? 0 : metaTypeNameSizes[i - 1] + calculateOffsetForIdx(i - 1);
}
static constexpr short calculateOffsetForTypeId(int typeId)
{
return calculateOffsetForIdx(findTypeId(typeId));
#if 0
// same as, but this is only valid in C++14:
short offset = 0;
for (int i = 0; i < MetaTypeNameCount; ++i) {
if (metaTypeIds[i] == typeId)
return offset;
offset += metaTypeNameSizes[i];
}
return -1;
#endif
}
short offsets[sizeof...(TypeIds)];
constexpr MetaTypeOffsets() : offsets{calculateOffsetForTypeId(TypeIds)...} {}
const char *operator[](int typeId) const Q_DECL_NOTHROW
{
short o = offsets[typeId];
return o < 0 ? nullptr : metaTypeStrings + o;
}
};
} // anonymous namespace
constexpr MetaTypeOffsets<QtPrivate::Indexes<QMetaType::HighestInternalId + 1>::Value> metaTypeNames {};
在qmetatype.h中,qt提供Q_DECLARE_METATYPE(TYPE) 宏来为用户自定义的类型进行注册。
//QtInstallDir\Src\qtbase\src\corelib\kernel\global.h
......
# define Q_DECL_EQ_DELETE = delete
#define Q_DISABLE_COPY(Class) \
Class(const Class &) Q_DECL_EQ_DELETE;\
Class &operator=(const Class &) Q_DECL_EQ_DELETE;
......
------------------------------------
//QtInstallDir\Src\qtbase\src\corelib\kernel\qmetatype.h
......
#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)\
.......
struct AbstractConverterFunction
{
typedef bool (*Converter)(const AbstractConverterFunction *, const void *, void*);
explicit AbstractConverterFunction(Converter c = nullptr)
: convert(c) {}
Q_DISABLE_COPY(AbstractConverterFunction)
Converter convert;
};
template<typename From, typename To>
struct ConverterMemberFunction : public AbstractConverterFunction
{
explicit ConverterMemberFunction(To(From::*function)() const)
: AbstractConverterFunction(convert),
m_function(function) {}
~ConverterMemberFunction();
static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
{
const From *f = static_cast<const From *>(in);
To *t = static_cast<To *>(out);
const ConverterMemberFunction *_typedThis =
static_cast<const ConverterMemberFunction *>(_this);
*t = (f->*_typedThis->m_function)();
return true;
}
To(From::* const m_function)() const;
};
template<typename From, typename To>
struct ConverterMemberFunctionOk : public AbstractConverterFunction
{
explicit ConverterMemberFunctionOk(To(From::*function)(bool *) const)
: AbstractConverterFunction(convert),
m_function(function) {}
~ConverterMemberFunctionOk();
static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
{
const From *f = static_cast<const From *>(in);
To *t = static_cast<To *>(out);
bool ok = false;
const ConverterMemberFunctionOk *_typedThis =
static_cast<const ConverterMemberFunctionOk *>(_this);
*t = (f->*_typedThis->m_function)(&ok);
if (!ok)
*t = To();
return ok;
}
To(From::* const m_function)(bool*) const;
};
template<typename From, typename To, typename UnaryFunction>
struct ConverterFunctor : public AbstractConverterFunction
{
explicit ConverterFunctor(UnaryFunction function)
: AbstractConverterFunction(convert),
m_function(function) {}
~ConverterFunctor();
static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
{
const From *f = static_cast<const From *>(in);
To *t = static_cast<To *>(out);
const ConverterFunctor *_typedThis =
static_cast<const ConverterFunctor *>(_this);
*t = _typedThis->m_function(*f);
return true;
}
UnaryFunction m_function;
};
......
#define Q_DECLARE_BUILTIN_METATYPE(TYPE, METATYPEID, NAME) \
QT_BEGIN_NAMESPACE \
template<> struct QMetaTypeId2<NAME> \
{ \
enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID }; \
static inline Q_DECL_CONSTEXPR int qt_metatype_id() { return METATYPEID; } \
}; \
QT_END_NAMESPACE
...........
QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
----------
//QtInstallDir\Src\qtbase\src\corelib\kernel\qmetatype.cpp
template<typename T, typename Key>
class QMetaTypeFunctionRegistry
{
public:
~QMetaTypeFunctionRegistry()
{
const QWriteLocker locker(&lock);
map.clear();
}
bool contains(Key k) const
{
const QReadLocker locker(&lock);
return map.contains(k);
}
bool insertIfNotContains(Key k, const T *f)
{
const QWriteLocker locker(&lock);
const T* &fun = map[k];
if (fun != 0)
return false;
fun = f;
return true;
}
const T *function(Key k) const
{
const QReadLocker locker(&lock);
return map.value(k, 0);
}
void remove(int from, int to)
{
const Key k(from, to);
const QWriteLocker locker(&lock);
map.remove(k);
}
private:
mutable QReadWriteLock lock;
QHash<Key, const T *> map;
};
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractConverterFunction,QPair<int,int> >
QMetaTypeConverterRegistry;
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractComparatorFunction,int>
QMetaTypeComparatorRegistry;
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int>
QMetaTypeDebugStreamRegistry;
bool QMetaType::registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to)
{
if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from, to), f)) {
qWarning("Type conversion already registered from type %s to type %s",
QMetaType::typeName(from), QMetaType::typeName(to));
return false;
}
return true;
}
/*!
\internal
Invoked automatically when a converter function object is destroyed.
*/
void QMetaType::unregisterConverterFunction(int from, int to)
{
if (customTypesConversionRegistry.isDestroyed())
return;
customTypesConversionRegistry()->remove(from, to);
}
bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId)
{
const QtPrivate::AbstractConverterFunction * const f =
customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId));
return f && f->convert(f, from, to);
}