1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2018 Intel Corporation.
5** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
6** Contact: https://www.qt.io/licensing/
7**
8** This file is part of the QtCore module of the Qt Toolkit.
9**
10** $QT_BEGIN_LICENSE:LGPL$
11** Commercial License Usage
12** Licensees holding valid commercial Qt licenses may use this file in
13** accordance with the commercial license agreement provided with the
14** Software or, alternatively, in accordance with the terms contained in
15** a written agreement between you and The Qt Company. For licensing terms
16** and conditions see https://www.qt.io/terms-conditions. For further
17** information use the contact form at https://www.qt.io/contact-us.
18**
19** GNU Lesser General Public License Usage
20** Alternatively, this file may be used under the terms of the GNU Lesser
21** General Public License version 3 as published by the Free Software
22** Foundation and appearing in the file LICENSE.LGPL3 included in the
23** packaging of this file. Please review the following information to
24** ensure the GNU Lesser General Public License version 3 requirements
25** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26**
27** GNU General Public License Usage
28** Alternatively, this file may be used under the terms of the GNU
29** General Public License version 2.0 or (at your option) the GNU General
30** Public license version 3 or any later version approved by the KDE Free
31** Qt Foundation. The licenses are as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33** included in the packaging of this file. Please review the following
34** information to ensure the GNU General Public License requirements will
35** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36** https://www.gnu.org/licenses/gpl-3.0.html.
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QMETATYPE_H
43#define QMETATYPE_H
44
45#include <QtCore/qglobal.h>
46#include <QtCore/qatomic.h>
47#include <QtCore/qbytearray.h>
48#include <QtCore/qcompare.h>
49#include <QtCore/qvarlengtharray.h>
50#include <QtCore/qrefcount.h>
51#include <QtCore/qdatastream.h>
52#include <QtCore/qiterable.h>
53#ifndef QT_NO_QOBJECT
54#include <QtCore/qobjectdefs.h>
55#endif
56
57#include <array>
58#include <new>
59#include <vector>
60#include <list>
61#include <map>
62#include <functional>
63
64#ifdef Bool
65#error qmetatype.h must be included before any header file that defines Bool
66#endif
67
68QT_BEGIN_NAMESPACE
69
70// from qcborcommon.h
71enum class QCborSimpleType : quint8;
72
73template <typename T>
74struct QMetaTypeId2;
75
76template <typename T>
77inline constexpr int qMetaTypeId();
78
79// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
80#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
81 F(Void, 43, void) \
82 F(Bool, 1, bool) \
83 F(Int, 2, int) \
84 F(UInt, 3, uint) \
85 F(LongLong, 4, qlonglong) \
86 F(ULongLong, 5, qulonglong) \
87 F(Double, 6, double) \
88 F(Long, 32, long) \
89 F(Short, 33, short) \
90 F(Char, 34, char) \
91 F(Char16, 56, char16_t) \
92 F(Char32, 57, char32_t) \
93 F(ULong, 35, ulong) \
94 F(UShort, 36, ushort) \
95 F(UChar, 37, uchar) \
96 F(Float, 38, float) \
97 F(SChar, 40, signed char) \
98 F(Nullptr, 51, std::nullptr_t) \
99 F(QCborSimpleType, 52, QCborSimpleType) \
100
101#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
102 F(VoidStar, 31, void*) \
103
104#if QT_CONFIG(easingcurve)
105#define QT_FOR_EACH_STATIC_EASINGCURVE(F)\
106 F(QEasingCurve, 29, QEasingCurve)
107#else
108#define QT_FOR_EACH_STATIC_EASINGCURVE(F)
109#endif
110
111#if QT_CONFIG(itemmodel)
112#define QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)\
113 F(QModelIndex, 42, QModelIndex) \
114 F(QPersistentModelIndex, 50, QPersistentModelIndex)
115#else
116#define QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
117#endif
118
119#if QT_CONFIG(regularexpression)
120# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
121 F(QRegularExpression, 44, QRegularExpression)
122#else
123# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F)
124#endif
125
126#define QT_FOR_EACH_STATIC_CORE_CLASS(F)\
127 F(QChar, 7, QChar) \
128 F(QString, 10, QString) \
129 F(QByteArray, 12, QByteArray) \
130 F(QBitArray, 13, QBitArray) \
131 F(QDate, 14, QDate) \
132 F(QTime, 15, QTime) \
133 F(QDateTime, 16, QDateTime) \
134 F(QUrl, 17, QUrl) \
135 F(QLocale, 18, QLocale) \
136 F(QRect, 19, QRect) \
137 F(QRectF, 20, QRectF) \
138 F(QSize, 21, QSize) \
139 F(QSizeF, 22, QSizeF) \
140 F(QLine, 23, QLine) \
141 F(QLineF, 24, QLineF) \
142 F(QPoint, 25, QPoint) \
143 F(QPointF, 26, QPointF) \
144 QT_FOR_EACH_STATIC_EASINGCURVE(F) \
145 F(QUuid, 30, QUuid) \
146 F(QVariant, 41, QVariant) \
147 QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
148 F(QJsonValue, 45, QJsonValue) \
149 F(QJsonObject, 46, QJsonObject) \
150 F(QJsonArray, 47, QJsonArray) \
151 F(QJsonDocument, 48, QJsonDocument) \
152 F(QCborValue, 53, QCborValue) \
153 F(QCborArray, 54, QCborArray) \
154 F(QCborMap, 55, QCborMap) \
155 QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
156
157#define QT_FOR_EACH_STATIC_CORE_POINTER(F)\
158 F(QObjectStar, 39, QObject*)
159
160#define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
161 F(QVariantMap, 8, QVariantMap) \
162 F(QVariantList, 9, QVariantList) \
163 F(QVariantHash, 28, QVariantHash) \
164 F(QVariantPair, 58, QVariantPair) \
165 F(QByteArrayList, 49, QByteArrayList) \
166 F(QStringList, 11, QStringList) \
167
168#if QT_CONFIG(shortcut)
169#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)\
170 F(QKeySequence, 0x100b, QKeySequence)
171#else
172#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)
173#endif
174
175#define QT_FOR_EACH_STATIC_GUI_CLASS(F)\
176 F(QFont, 0x1000, QFont) \
177 F(QPixmap, 0x1001, QPixmap) \
178 F(QBrush, 0x1002, QBrush) \
179 F(QColor, 0x1003, QColor) \
180 F(QPalette, 0x1004, QPalette) \
181 F(QIcon, 0x1005, QIcon) \
182 F(QImage, 0x1006, QImage) \
183 F(QPolygon, 0x1007, QPolygon) \
184 F(QRegion, 0x1008, QRegion) \
185 F(QBitmap, 0x1009, QBitmap) \
186 F(QCursor, 0x100a, QCursor) \
187 QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F) \
188 F(QPen, 0x100c, QPen) \
189 F(QTextLength, 0x100d, QTextLength) \
190 F(QTextFormat, 0x100e, QTextFormat) \
191 F(QTransform, 0x1010, QTransform) \
192 F(QMatrix4x4, 0x1011, QMatrix4x4) \
193 F(QVector2D, 0x1012, QVector2D) \
194 F(QVector3D, 0x1013, QVector3D) \
195 F(QVector4D, 0x1014, QVector4D) \
196 F(QQuaternion, 0x1015, QQuaternion) \
197 F(QPolygonF, 0x1016, QPolygonF) \
198 F(QColorSpace, 0x1017, QColorSpace) \
199
200
201#define QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\
202 F(QSizePolicy, 0x2000, QSizePolicy) \
203
204// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, AliasingType, "RealType")
205#define QT_FOR_EACH_STATIC_ALIAS_TYPE(F)\
206 F(ULong, -1, ulong, "unsigned long") \
207 F(UInt, -1, uint, "unsigned int") \
208 F(UShort, -1, ushort, "unsigned short") \
209 F(UChar, -1, uchar, "unsigned char") \
210 F(LongLong, -1, qlonglong, "long long") \
211 F(ULongLong, -1, qulonglong, "unsigned long long") \
212 F(SChar, -1, signed char, "qint8") \
213 F(UChar, -1, uchar, "quint8") \
214 F(Short, -1, short, "qint16") \
215 F(UShort, -1, ushort, "quint16") \
216 F(Int, -1, int, "qint32") \
217 F(UInt, -1, uint, "quint32") \
218 F(LongLong, -1, qlonglong, "qint64") \
219 F(ULongLong, -1, qulonglong, "quint64") \
220 F(QVariantList, -1, QVariantList, "QList<QVariant>") \
221 F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
222 F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
223 F(QVariantPair, -1, QVariantPair, "QPair<QVariant,QVariant>") \
224 F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
225 F(QStringList, -1, QStringList, "QList<QString>") \
226
227#define QT_FOR_EACH_STATIC_TYPE(F)\
228 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
229 QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
230 QT_FOR_EACH_STATIC_CORE_CLASS(F)\
231 QT_FOR_EACH_STATIC_CORE_POINTER(F)\
232 QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
233 QT_FOR_EACH_STATIC_GUI_CLASS(F)\
234 QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\
235
236#define QT_DEFINE_METATYPE_ID(TypeName, Id, Name) \
237 TypeName = Id,
238
239#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \
240 F(QList) \
241 F(QQueue) \
242 F(QStack) \
243 F(QSet) \
244 /*end*/
245
246#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(F) \
247 F(QHash, class) \
248 F(QMap, class)
249
250#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(F) \
251 F(QSharedPointer) \
252 F(QWeakPointer) \
253 F(QPointer)
254
255class QDataStream;
256struct QMetaObject;
257
258namespace QtPrivate
259{
260
261class QMetaTypeInterface
262{
263public:
264 ushort revision; // 0 in Qt 6.0. Can increase if new field are added
265 ushort alignment;
266 uint size;
267 uint flags;
268 mutable QBasicAtomicInt typeId;
269
270 using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
271 MetaObjectFn metaObjectFn;
272
273 const char *name;
274
275 using DefaultCtrFn = void (*)(const QMetaTypeInterface *, void *);
276 DefaultCtrFn defaultCtr;
277 using CopyCtrFn = void (*)(const QMetaTypeInterface *, void *, const void *);
278 CopyCtrFn copyCtr;
279 using MoveCtrFn = void (*)(const QMetaTypeInterface *, void *, void *);
280 MoveCtrFn moveCtr;
281 using DtorFn = void (*)(const QMetaTypeInterface *, void *);
282 DtorFn dtor;
283 using EqualsFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
284 EqualsFn equals;
285 using LessThanFn = bool (*)(const QMetaTypeInterface *, const void *, const void *);
286 LessThanFn lessThan;
287 using DebugStreamFn = void (*)(const QMetaTypeInterface *, QDebug &, const void *);
288 DebugStreamFn debugStream;
289 using DataStreamOutFn = void (*)(const QMetaTypeInterface *, QDataStream &, const void *);
290 DataStreamOutFn dataStreamOut;
291 using DataStreamInFn = void (*)(const QMetaTypeInterface *, QDataStream &, void *);
292 DataStreamInFn dataStreamIn;
293
294 using LegacyRegisterOp = void (*)();
295 LegacyRegisterOp legacyRegisterOp;
296};
297
298/*!
299 This template is used for implicit conversion from type From to type To.
300 \internal
301*/
302template<typename From, typename To>
303To convertImplicit(const From& from)
304{
305 return from;
306}
307
308 template<typename T, bool>
309 struct SequentialValueTypeIsMetaType;
310 template<typename T, bool>
311 struct AssociativeValueTypeIsMetaType;
312 template<typename T, bool>
313 struct IsMetaTypePair;
314 template<typename, typename>
315 struct MetaTypeSmartPointerHelper;
316
317 template<typename T>
318 struct IsQFlags : std::false_type {};
319
320 template<typename Enum>
321 struct IsQFlags<QFlags<Enum>> : std::true_type {};
322
323 template<typename T>
324 struct IsEnumOrFlags : std::disjunction<std::is_enum<T>, IsQFlags<T>> {};
325} // namespace QtPrivate
326
327class Q_CORE_EXPORT QMetaType {
328public:
329#ifndef Q_CLANG_QDOC
330 // The code that actually gets compiled.
331 enum Type {
332 // these are merged with QVariant
333 QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
334
335 FirstCoreType = Bool,
336 LastCoreType = QVariantPair,
337 FirstGuiType = QFont,
338 LastGuiType = QColorSpace,
339 FirstWidgetsType = QSizePolicy,
340 LastWidgetsType = QSizePolicy,
341 HighestInternalId = LastWidgetsType,
342
343 QReal = sizeof(qreal) == sizeof(double) ? Double : Float,
344
345 UnknownType = 0,
346 User = 65536
347 };
348#else
349 // If we are using QDoc it fakes the Type enum looks like this.
350 enum Type {
351 UnknownType = 0, Bool = 1, Int = 2, UInt = 3, LongLong = 4, ULongLong = 5,
352 Double = 6, Long = 32, Short = 33, Char = 34, ULong = 35, UShort = 36,
353 UChar = 37, Float = 38,
354 VoidStar = 31,
355 QChar = 7, QString = 10, QStringList = 11, QByteArray = 12,
356 QBitArray = 13, QDate = 14, QTime = 15, QDateTime = 16, QUrl = 17,
357 QLocale = 18, QRect = 19, QRectF = 20, QSize = 21, QSizeF = 22,
358 QLine = 23, QLineF = 24, QPoint = 25, QPointF = 26,
359 QEasingCurve = 29, QUuid = 30, QVariant = 41, QModelIndex = 42,
360 QPersistentModelIndex = 50, QRegularExpression = 44,
361 QJsonValue = 45, QJsonObject = 46, QJsonArray = 47, QJsonDocument = 48,
362 QByteArrayList = 49, QObjectStar = 39, SChar = 40,
363 Void = 43,
364 Nullptr = 51,
365 QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
366 QCborSimpleType = 52, QCborValue = 53, QCborArray = 54, QCborMap = 55,
367 Char16 = 56, Char32 = 57,
368
369 // Gui types
370 QFont = 0x1000, QPixmap = 0x1001, QBrush = 0x1002, QColor = 0x1003, QPalette = 0x1004,
371 QIcon = 0x1005, QImage = 0x1006, QPolygon = 0x1007, QRegion = 0x1008, QBitmap = 0x1009,
372 QCursor = 0x100a, QKeySequence = 0x100b, QPen = 0x100c, QTextLength = 0x100d, QTextFormat = 0x100e,
373 QTransform = 0x1010, QMatrix4x4 = 0x1011, QVector2D = 0x1012,
374 QVector3D = 0x1013, QVector4D = 0x1014, QQuaternion = 0x1015, QPolygonF = 0x1016, QColorSpace = 0x1017,
375
376 // Widget types
377 QSizePolicy = 0x2000,
378 LastCoreType = Char32,
379 LastGuiType = QColorSpace,
380 User = 65536
381 };
382#endif
383
384 enum TypeFlag {
385 NeedsConstruction = 0x1,
386 NeedsDestruction = 0x2,
387 RelocatableType = 0x4,
388#if QT_DEPRECATED_SINCE(6, 0)
389 MovableType Q_DECL_ENUMERATOR_DEPRECATED_X("Use RelocatableType instead.") = RelocatableType,
390#endif
391 PointerToQObject = 0x8,
392 IsEnumeration = 0x10,
393 SharedPointerToQObject = 0x20,
394 WeakPointerToQObject = 0x40,
395 TrackingPointerToQObject = 0x80,
396 IsUnsignedEnumeration = 0x100,
397 IsGadget = 0x200,
398 PointerToGadget = 0x400,
399 IsPointer = 0x800,
400 IsQmlList =0x1000, // used in the QML engine to recognize QQmlListProperty<T> and list<T>
401 IsConst = 0x2000,
402 };
403 Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
404
405 static void registerNormalizedTypedef(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, QMetaType type);
406
407#if QT_DEPRECATED_SINCE(6, 0)
408 QT_DEPRECATED_VERSION_6_0
409 static int type(const char *typeName)
410 { return QMetaType::fromName(typeName).id(); }
411 QT_DEPRECATED_VERSION_6_0
412 static int type(const QT_PREPEND_NAMESPACE(QByteArray) &typeName)
413 { return QMetaType::fromName(typeName).id(); }
414 QT_DEPRECATED_VERSION_6_0
415 static const char *typeName(int type)
416 { return QMetaType(type).name(); }
417 QT_DEPRECATED_VERSION_6_0
418 static int sizeOf(int type)
419 { return QMetaType(type).sizeOf(); }
420 QT_DEPRECATED_VERSION_6_0
421 static TypeFlags typeFlags(int type)
422 { return QMetaType(type).flags(); }
423 QT_DEPRECATED_VERSION_6_0
424 static const QMetaObject *metaObjectForType(int type)
425 { return QMetaType(type).metaObject(); }
426 QT_DEPRECATED_VERSION_6_0
427 static void *create(int type, const void *copy = nullptr)
428 { return QMetaType(type).create(copy); }
429 QT_DEPRECATED_VERSION_6_0
430 static void destroy(int type, void *data)
431 { return QMetaType(type).destroy(data); }
432 QT_DEPRECATED_VERSION_6_0
433 static void *construct(int type, void *where, const void *copy)
434 { return QMetaType(type).construct(where, copy); }
435 QT_DEPRECATED_VERSION_6_0
436 static void destruct(int type, void *where)
437 { return QMetaType(type).destruct(where); }
438#endif
439 static bool isRegistered(int type);
440
441 explicit QMetaType(int type);
442 explicit constexpr QMetaType(const QtPrivate::QMetaTypeInterface *d) : d_ptr(d) {}
443 constexpr QMetaType() = default;
444
445 bool isValid() const;
446 bool isRegistered() const;
447#if defined(QT_QMETATYPE_BC_COMPAT) || defined(Q_QDOC)
448 int id() const;
449#else
450 // ### Qt 7: Remove traces of out of line version
451 // unused int parameter is used to avoid ODR violation
452 int id(int = 0) const
453 {
454 if (d_ptr) {
455 if (int id = d_ptr->typeId.loadRelaxed())
456 return id;
457 return idHelper();
458 }
459 return 0;
460 };
461#endif
462 constexpr qsizetype sizeOf() const;
463 constexpr qsizetype alignOf() const;
464 constexpr TypeFlags flags() const;
465 constexpr const QMetaObject *metaObject() const;
466 constexpr const char *name() const;
467
468 void *create(const void *copy = nullptr) const;
469 void destroy(void *data) const;
470 void *construct(void *where, const void *copy = nullptr) const;
471 void destruct(void *data) const;
472 QPartialOrdering compare(const void *lhs, const void *rhs) const;
473 bool equals(const void *lhs, const void *rhs) const;
474
475 bool isEqualityComparable() const;
476 bool isOrdered() const;
477
478#ifndef QT_NO_DATASTREAM
479 bool save(QDataStream &stream, const void *data) const;
480 bool load(QDataStream &stream, void *data) const;
481 bool hasRegisteredDataStreamOperators() const;
482
483#if QT_DEPRECATED_SINCE(6, 0)
484 QT_DEPRECATED_VERSION_6_0
485 static bool save(QDataStream &stream, int type, const void *data)
486 { return QMetaType(type).save(stream, data); }
487 QT_DEPRECATED_VERSION_6_0
488 static bool load(QDataStream &stream, int type, void *data)
489 { return QMetaType(type).load(stream, data); }
490#endif
491#endif
492
493 template<typename T>
494 constexpr static QMetaType fromType();
495 static QMetaType fromName(QByteArrayView name);
496
497 friend bool operator==(QMetaType a, QMetaType b)
498 {
499 if (a.d_ptr == b.d_ptr)
500 return true;
501 if (!a.d_ptr || !b.d_ptr)
502 return false; // one type is undefined, the other is defined
503 // avoid id call if we already have the id
504 const int aId = a.id();
505 const int bId = b.id();
506 return aId == bId;
507 }
508 friend bool operator!=(QMetaType a, QMetaType b) { return !(a == b); }
509
510public:
511
512#ifndef QT_NO_DEBUG_STREAM
513 bool debugStream(QDebug& dbg, const void *rhs);
514 bool hasRegisteredDebugStreamOperator() const;
515
516#if QT_DEPRECATED_SINCE(6, 0)
517 QT_DEPRECATED_VERSION_6_0
518 static bool debugStream(QDebug& dbg, const void *rhs, int typeId)
519 { return QMetaType(typeId).debugStream(dbg, rhs); }
520 template<typename T>
521 QT_DEPRECATED_VERSION_6_0
522 static bool hasRegisteredDebugStreamOperator()
523 { return QMetaType::fromType<T>().hasRegisteredDebugStreamOperator(); }
524 QT_DEPRECATED_VERSION_6_0
525 static bool hasRegisteredDebugStreamOperator(int typeId)
526 { return QMetaType(typeId).hasRegisteredDebugStreamOperator(); }
527#endif
528#endif
529
530 // type erased converter function
531 using ConverterFunction = std::function<bool(const void *src, void *target)>;
532
533 // type erased mutable view, primarily for containers
534 using MutableViewFunction = std::function<bool(void *src, void *target)>;
535
536 // implicit conversion supported like double -> float
537 template<typename From, typename To>
538 static bool registerConverter()
539 {
540 return registerConverter<From, To>(QtPrivate::convertImplicit<From, To>);
541 }
542
543#ifdef Q_CLANG_QDOC
544 template<typename MemberFunction, int>
545 static bool registerConverter(MemberFunction function);
546 template<typename MemberFunctionOk, char>
547 static bool registerConverter(MemberFunctionOk function);
548 template<typename UnaryFunction>
549 static bool registerConverter(UnaryFunction function);
550
551 template<typename MemberFunction, int>
552 static bool registerMutableView(MemberFunction function);
553 template<typename MemberFunctionOk, char>
554 static bool registerMutableView(MemberFunctionOk function);
555 template<typename UnaryFunction>
556 static bool registerMutableView(UnaryFunction function);
557#else
558 // member function as in "QString QFont::toString() const"
559 template<typename From, typename To>
560 static bool registerConverter(To(From::*function)() const)
561 {
562 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
563 "QMetaType::registerConverter: At least one of the types must be a custom type.");
564
565 const QMetaType fromType = QMetaType::fromType<From>();
566 const QMetaType toType = QMetaType::fromType<To>();
567 auto converter = [function](const void *from, void *to) -> bool {
568 const From *f = static_cast<const From *>(from);
569 To *t = static_cast<To *>(to);
570 *t = (f->*function)();
571 return true;
572 };
573 return registerConverterFunction(converter, fromType, toType);
574 }
575
576 // member function
577 template<typename From, typename To>
578 static bool registerMutableView(To(From::*function)())
579 {
580 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
581 "QMetaType::registerMutableView: At least one of the types must be a custom type.");
582
583 const QMetaType fromType = QMetaType::fromType<From>();
584 const QMetaType toType = QMetaType::fromType<To>();
585 auto view = [function](void *from, void *to) -> bool {
586 From *f = static_cast<From *>(from);
587 To *t = static_cast<To *>(to);
588 *t = (f->*function)();
589 return true;
590 };
591 return registerMutableViewFunction(view, fromType, toType);
592 }
593
594 // member function as in "double QString::toDouble(bool *ok = nullptr) const"
595 template<typename From, typename To>
596 static bool registerConverter(To(From::*function)(bool*) const)
597 {
598 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
599 "QMetaType::registerConverter: At least one of the types must be a custom type.");
600
601 const QMetaType fromType = QMetaType::fromType<From>();
602 const QMetaType toType = QMetaType::fromType<To>();
603 auto converter = [function](const void *from, void *to) -> bool {
604 const From *f = static_cast<const From *>(from);
605 To *t = static_cast<To *>(to);
606 bool result = true;
607 *t = (f->*function)(&result);
608 if (!result)
609 *t = To();
610 return result;
611 };
612 return registerConverterFunction(converter, fromType, toType);
613 }
614
615 // functor or function pointer
616 template<typename From, typename To, typename UnaryFunction>
617 static bool registerConverter(UnaryFunction function)
618 {
619 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
620 "QMetaType::registerConverter: At least one of the types must be a custom type.");
621
622 const QMetaType fromType = QMetaType::fromType<From>();
623 const QMetaType toType = QMetaType::fromType<To>();
624 auto converter = [function](const void *from, void *to) -> bool {
625 const From *f = static_cast<const From *>(from);
626 To *t = static_cast<To *>(to);
627 *t = function(*f);
628 return true;
629 };
630 return registerConverterFunction(converter, fromType, toType);
631 }
632
633 // functor or function pointer
634 template<typename From, typename To, typename UnaryFunction>
635 static bool registerMutableView(UnaryFunction function)
636 {
637 static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
638 "QMetaType::registerMutableView: At least one of the types must be a custom type.");
639
640 const QMetaType fromType = QMetaType::fromType<From>();
641 const QMetaType toType = QMetaType::fromType<To>();
642 auto view = [function](void *from, void *to) -> bool {
643 From *f = static_cast<From *>(from);
644 To *t = static_cast<To *>(to);
645 *t = function(*f);
646 return true;
647 };
648 return registerMutableViewFunction(view, fromType, toType);
649 }
650#endif
651
652 static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to);
653 static bool canConvert(QMetaType fromType, QMetaType toType);
654
655 static bool view(QMetaType fromType, void *from, QMetaType toType, void *to);
656 static bool canView(QMetaType fromType, QMetaType toType);
657#if QT_DEPRECATED_SINCE(6, 0)
658 QT_DEPRECATED_VERSION_6_0
659 static bool convert(const void *from, int fromTypeId, void *to, int toTypeId)
660 { return convert(QMetaType(fromTypeId), from, QMetaType(toTypeId), to); }
661 QT_DEPRECATED_VERSION_6_0
662 static bool compare(const void *lhs, const void *rhs, int typeId, int *result)
663 {
664 QMetaType t(typeId);
665 auto c = t.compare(lhs, rhs);
666 if (c == QPartialOrdering::Unordered) {
667 *result = 0;
668 return false;
669 } else if (c == QPartialOrdering::Less) {
670 *result = -1;
671 return true;
672 } else if (c == QPartialOrdering::Equivalent) {
673 *result = 0;
674 return true;
675 } else {
676 *result = 1;
677 return true;
678 }
679 }
680 QT_DEPRECATED_VERSION_6_0
681 static bool equals(const void *lhs, const void *rhs, int typeId, int *result)
682 {
683 QMetaType t(typeId);
684 if (!t.isEqualityComparable())
685 return false;
686 *result = t.equals(lhs, rhs) ? 0 : -1;
687 return true;
688 }
689#endif
690
691 template<typename From, typename To>
692 static bool hasRegisteredConverterFunction()
693 {
694 return hasRegisteredConverterFunction(
695 QMetaType::fromType<From>(), QMetaType::fromType<To>());
696 }
697
698 static bool hasRegisteredConverterFunction(QMetaType fromType, QMetaType toType);
699
700 template<typename From, typename To>
701 static bool hasRegisteredMutableViewFunction()
702 {
703 return hasRegisteredMutableViewFunction(
704 QMetaType::fromType<From>(), QMetaType::fromType<To>());
705 }
706
707 static bool hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType);
708
709#ifndef Q_CLANG_QDOC
710 template<typename, bool> friend struct QtPrivate::SequentialValueTypeIsMetaType;
711 template<typename, bool> friend struct QtPrivate::AssociativeValueTypeIsMetaType;
712 template<typename, bool> friend struct QtPrivate::IsMetaTypePair;
713 template<typename, typename> friend struct QtPrivate::MetaTypeSmartPointerHelper;
714#endif
715 static bool registerConverterFunction(const ConverterFunction &f, QMetaType from, QMetaType to);
716 static void unregisterConverterFunction(QMetaType from, QMetaType to);
717
718 static bool registerMutableViewFunction(const MutableViewFunction &f, QMetaType from, QMetaType to);
719 static void unregisterMutableViewFunction(QMetaType from, QMetaType to);
720
721 static void unregisterMetaType(QMetaType type);
722 const QtPrivate::QMetaTypeInterface *iface() { return d_ptr; }
723
724private:
725 int idHelper() const;
726 friend class QVariant;
727 const QtPrivate::QMetaTypeInterface *d_ptr = nullptr;
728};
729
730#undef QT_DEFINE_METATYPE_ID
731
732Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaType::TypeFlags)
733
734#define QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(C, F) \
735 } \
736 Q_DECLARE_TYPEINFO(QtMetaTypePrivate:: C, (F)); \
737 namespace QtMetaTypePrivate {
738
739
740namespace QtMetaTypePrivate {
741
742class QPairVariantInterfaceImpl
743{
744public:
745 const void *_pair;
746 QMetaType _metaType_first;
747 QMetaType _metaType_second;
748
749 typedef void (*getFunc)(const void * const *p, void *);
750
751 getFunc _getFirst;
752 getFunc _getSecond;
753
754 template<class T>
755 static void getFirstImpl(const void * const *pair, void *dataPtr)
756 { *static_cast<typename T::first_type *>(dataPtr) = static_cast<const T*>(*pair)->first; }
757 template<class T>
758 static void getSecondImpl(const void * const *pair, void *dataPtr)
759 { *static_cast<typename T::second_type *>(dataPtr) = static_cast<const T*>(*pair)->second; }
760
761public:
762 template<class T> QPairVariantInterfaceImpl(const T*p)
763 : _pair(p)
764 , _metaType_first(QMetaType::fromType<typename T::first_type>())
765 , _metaType_second(QMetaType::fromType<typename T::second_type>())
766 , _getFirst(getFirstImpl<T>)
767 , _getSecond(getSecondImpl<T>)
768 {
769 }
770
771 constexpr QPairVariantInterfaceImpl()
772 : _pair(nullptr)
773 , _getFirst(nullptr)
774 , _getSecond(nullptr)
775 {
776 }
777
778 inline void first(void *dataPtr) const { _getFirst(&_pair, dataPtr); }
779 inline void second(void *dataPtr) const { _getSecond(&_pair, dataPtr); }
780};
781QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QPairVariantInterfaceImpl, Q_RELOCATABLE_TYPE)
782
783template<typename From>
784struct QPairVariantInterfaceConvertFunctor;
785
786template<typename T, typename U>
787struct QPairVariantInterfaceConvertFunctor<std::pair<T, U> >
788{
789 QPairVariantInterfaceImpl operator()(const std::pair<T, U>& f) const
790 {
791 return QPairVariantInterfaceImpl(&f);
792 }
793};
794
795}
796
797class QObject;
798
799#define QT_FORWARD_DECLARE_SHARED_POINTER_TYPES_ITER(Name) \
800 template <class T> class Name; \
801
802QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(QT_FORWARD_DECLARE_SHARED_POINTER_TYPES_ITER)
803
804namespace QtPrivate
805{
806 template<typename T>
807 struct IsPointerToTypeDerivedFromQObject
808 {
809 enum { Value = false };
810 };
811
812 // Specialize to avoid sizeof(void) warning
813 template<>
814 struct IsPointerToTypeDerivedFromQObject<void*>
815 {
816 enum { Value = false };
817 };
818 template<>
819 struct IsPointerToTypeDerivedFromQObject<const void*>
820 {
821 enum { Value = false };
822 };
823 template<>
824 struct IsPointerToTypeDerivedFromQObject<QObject*>
825 {
826 enum { Value = true };
827 };
828
829 template<typename T>
830 struct IsPointerToTypeDerivedFromQObject<T*>
831 {
832 typedef qint8 yes_type;
833 typedef qint64 no_type;
834
835#ifndef QT_NO_QOBJECT
836 static yes_type checkType(QObject* );
837 static yes_type checkType(const QObject* );
838#endif
839 static no_type checkType(...);
840 static_assert(sizeof(T), "Type argument of Q_PROPERTY or Q_DECLARE_METATYPE(T*) must be fully defined");
841 enum { Value = sizeof(checkType(static_cast<T*>(nullptr))) == sizeof(yes_type) };
842 };
843
844 template<typename T, typename Enable = void>
845 struct IsGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
846
847 template<typename T>
848 struct IsGadgetHelper<T, typename T::QtGadgetHelper>
849 {
850 template <typename X>
851 static char checkType(void (X::*)());
852 static void *checkType(void (T::*)());
853 enum {
854 IsRealGadget = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
855 IsGadgetOrDerivedFrom = true
856 };
857 };
858
859 template<typename T, typename Enable = void>
860 struct IsPointerToGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
861
862 template<typename T>
863 struct IsPointerToGadgetHelper<T*, typename T::QtGadgetHelper>
864 {
865 using BaseType = T;
866 template <typename X>
867 static char checkType(void (X::*)());
868 static void *checkType(void (T::*)());
869 enum {
870 IsRealGadget = !IsPointerToTypeDerivedFromQObject<T*>::Value && sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
871 IsGadgetOrDerivedFrom = !IsPointerToTypeDerivedFromQObject<T*>::Value
872 };
873 };
874
875
876 template<typename T> char qt_getEnumMetaObject(const T&);
877
878 template<typename T>
879 struct IsQEnumHelper {
880 static const T &declval();
881 // If the type was declared with Q_ENUM, the friend qt_getEnumMetaObject() declared in the
882 // Q_ENUM macro will be chosen by ADL, and the return type will be QMetaObject*.
883 // Otherwise the chosen overload will be the catch all template function
884 // qt_getEnumMetaObject(T) which returns 'char'
885 enum { Value = sizeof(qt_getEnumMetaObject(declval())) == sizeof(QMetaObject*) };
886 };
887 template<> struct IsQEnumHelper<void> { enum { Value = false }; };
888
889 template<typename T, typename Enable = void>
890 struct MetaObjectForType
891 {
892 static constexpr const QMetaObject *value() { return nullptr; }
893 using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
894 static constexpr MetaObjectFn metaObjectFunction = nullptr;
895 };
896#ifndef QT_NO_QOBJECT
897 template<>
898 struct MetaObjectForType<void>
899 {
900 static constexpr const QMetaObject *value() { return nullptr; }
901 using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
902 static constexpr MetaObjectFn metaObjectFunction = nullptr;
903 };
904 template<typename T>
905 struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type>
906 {
907 static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
908 static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
909 };
910 template<typename T>
911 struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
912 {
913 static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
914 static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
915 };
916 template<typename T>
917 struct MetaObjectForType<T, typename std::enable_if<IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
918 {
919 static constexpr const QMetaObject *value()
920 {
921 return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject;
922 }
923 static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return value(); }
924 };
925 template<typename T>
926 struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type >
927 {
928 static constexpr const QMetaObject *value() { return qt_getEnumMetaObject(T()); }
929 static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return value(); }
930 };
931#endif
932
933 template<typename T>
934 struct IsSharedPointerToTypeDerivedFromQObject
935 {
936 enum { Value = false };
937 };
938
939 template<typename T>
940 struct IsSharedPointerToTypeDerivedFromQObject<QSharedPointer<T> > : IsPointerToTypeDerivedFromQObject<T*>
941 {
942 };
943
944 template<typename T>
945 struct IsWeakPointerToTypeDerivedFromQObject
946 {
947 enum { Value = false };
948 };
949
950 template<typename T>
951 struct IsWeakPointerToTypeDerivedFromQObject<QWeakPointer<T> > : IsPointerToTypeDerivedFromQObject<T*>
952 {
953 };
954
955 template<typename T>
956 struct IsTrackingPointerToTypeDerivedFromQObject
957 {
958 enum { Value = false };
959 };
960
961 template<typename T>
962 struct IsTrackingPointerToTypeDerivedFromQObject<QPointer<T> >
963 {
964 enum { Value = true };
965 };
966
967 template<typename T>
968 struct IsSequentialContainer
969 {
970 enum { Value = false };
971 };
972
973 template<typename T>
974 struct IsAssociativeContainer
975 {
976 enum { Value = false };
977 };
978
979 template<typename T, bool = QtPrivate::IsSequentialContainer<T>::Value>
980 struct SequentialContainerTransformationHelper
981 {
982 static bool registerConverter()
983 {
984 return false;
985 }
986
987 static bool registerMutableView()
988 {
989 return false;
990 }
991 };
992
993 template<typename T, bool = QMetaTypeId2<typename T::value_type>::Defined>
994 struct SequentialValueTypeIsMetaType
995 {
996 static bool registerConverter()
997 {
998 return false;
999 }
1000
1001 static bool registerMutableView()
1002 {
1003 return false;
1004 }
1005 };
1006
1007 template<typename T>
1008 struct SequentialContainerTransformationHelper<T, true> : SequentialValueTypeIsMetaType<T>
1009 {
1010 };
1011
1012 template<typename T, bool = QtPrivate::IsAssociativeContainer<T>::Value>
1013 struct AssociativeContainerTransformationHelper
1014 {
1015 static bool registerConverter()
1016 {
1017 return false;
1018 }
1019
1020 static bool registerMutableView()
1021 {
1022 return false;
1023 }
1024 };
1025
1026 template<typename T, bool = QMetaTypeId2<typename T::key_type>::Defined>
1027 struct AssociativeKeyTypeIsMetaType
1028 {
1029 static bool registerConverter()
1030 {
1031 return false;
1032 }
1033
1034 static bool registerMutableView()
1035 {
1036 return false;
1037 }
1038 };
1039
1040 template<typename T, bool = QMetaTypeId2<typename T::mapped_type>::Defined>
1041 struct AssociativeMappedTypeIsMetaType
1042 {
1043 static bool registerConverter()
1044 {
1045 return false;
1046 }
1047
1048 static bool registerMutableView()
1049 {
1050 return false;
1051 }
1052 };
1053
1054 template<typename T>
1055 struct AssociativeContainerTransformationHelper<T, true> : AssociativeKeyTypeIsMetaType<T>
1056 {
1057 };
1058
1059 template<typename T, bool = QMetaTypeId2<typename T::first_type>::Defined
1060 && QMetaTypeId2<typename T::second_type>::Defined>
1061 struct IsMetaTypePair
1062 {
1063 static bool registerConverter()
1064 {
1065 return false;
1066 }
1067 };
1068
1069 template<typename T>
1070 struct IsMetaTypePair<T, true>
1071 {
1072 inline static bool registerConverter();
1073 };
1074
1075 template<typename T>
1076 struct IsPair
1077 {
1078 static bool registerConverter()
1079 {
1080 return false;
1081 }
1082 };
1083 template<typename T, typename U>
1084 struct IsPair<std::pair<T, U> > : IsMetaTypePair<std::pair<T, U> > {};
1085
1086 template<typename T>
1087 struct MetaTypePairHelper : IsPair<T> {};
1088
1089 template<typename T, typename = void>
1090 struct MetaTypeSmartPointerHelper
1091 {
1092 static bool registerConverter() { return false; }
1093 };
1094
1095 Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type);
1096} // namespace QtPrivate
1097
1098template <typename T, int =
1099 QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
1100 QtPrivate::IsGadgetHelper<T>::IsRealGadget ? QMetaType::IsGadget :
1101 QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget :
1102 QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0>
1103struct QMetaTypeIdQObject
1104{
1105 enum {
1106 Defined = 0
1107 };
1108};
1109
1110template <typename T>
1111struct QMetaTypeId : public QMetaTypeIdQObject<T>
1112{
1113};
1114
1115template <typename T>
1116struct QMetaTypeId2
1117{
1118 using NameAsArrayType = void;
1119 enum { Defined = QMetaTypeId<T>::Defined, IsBuiltIn=false };
1120 static inline constexpr int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); }
1121};
1122
1123template <typename T>
1124struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {};
1125
1126template <typename T>
1127struct QMetaTypeId2<T&> { enum {Defined = false }; };
1128
1129namespace QtPrivate {
1130 template <typename T, bool Defined = QMetaTypeId2<T>::Defined>
1131 struct QMetaTypeIdHelper {
1132 static inline constexpr int qt_metatype_id()
1133 { return QMetaTypeId2<T>::qt_metatype_id(); }
1134 };
1135 template <typename T> struct QMetaTypeIdHelper<T, false> {
1136 static inline constexpr int qt_metatype_id()
1137 { return -1; }
1138 };
1139
1140 // Function pointers don't derive from QObject
1141 template <typename Result, typename... Args>
1142 struct IsPointerToTypeDerivedFromQObject<Result(*)(Args...)> { enum { Value = false }; };
1143
1144 template<typename T>
1145 inline constexpr bool IsQmlListType = false;
1146
1147 template<typename T, bool = std::is_enum<T>::value>
1148 constexpr bool IsUnsignedEnum = false;
1149 template<typename T>
1150 constexpr bool IsUnsignedEnum<T, true> = !std::is_signed_v<std::underlying_type_t<T>>;
1151
1152 template<typename T>
1153 struct QMetaTypeTypeFlags
1154 {
1155 enum { Flags = (QTypeInfo<T>::isRelocatable ? QMetaType::RelocatableType : 0)
1156 | (QTypeInfo<T>::isComplex ? QMetaType::NeedsConstruction : 0)
1157 | (QTypeInfo<T>::isComplex ? QMetaType::NeedsDestruction : 0)
1158 | (IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : 0)
1159 | (IsSharedPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::SharedPointerToQObject : 0)
1160 | (IsWeakPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::WeakPointerToQObject : 0)
1161 | (IsTrackingPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::TrackingPointerToQObject : 0)
1162 | (IsEnumOrFlags<T>::value ? QMetaType::IsEnumeration : 0)
1163 | (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0)
1164 | (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0)
1165 | (QTypeInfo<T>::isPointer ? QMetaType::IsPointer : 0)
1166 | (IsUnsignedEnum<T> ? QMetaType::IsUnsignedEnumeration : 0)
1167 | (IsQmlListType<T> ? QMetaType::IsQmlList : 0)
1168 | (std::is_const_v<std::remove_pointer_t<T>> ? QMetaType::IsConst : 0)
1169 };
1170 };
1171
1172 template<typename T, bool defined>
1173 struct MetaTypeDefinedHelper
1174 {
1175 enum DefinedType { Defined = defined };
1176 };
1177
1178 template<typename SmartPointer>
1179 struct QSmartPointerConvertFunctor
1180 {
1181 QObject* operator()(const SmartPointer &p) const
1182 {
1183 return p.operator->();
1184 }
1185 };
1186
1187 // hack to delay name lookup to instantiation time by making
1188 // EnableInternalData a dependent name:
1189 template <typename T>
1190 struct EnableInternalDataWrap;
1191
1192 template<typename T>
1193 struct QSmartPointerConvertFunctor<QWeakPointer<T> >
1194 {
1195 QObject* operator()(const QWeakPointer<T> &p) const
1196 {
1197 return QtPrivate::EnableInternalDataWrap<T>::internalData(p);
1198 }
1199 };
1200}
1201
1202template <typename T>
1203int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
1204{
1205#ifndef QT_NO_QOBJECT
1206 Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), "qRegisterNormalizedMetaType", "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead.");
1207#endif
1208
1209 const QMetaType metaType = QMetaType::fromType<T>();
1210 const int id = metaType.id();
1211
1212 if (id > 0) {
1213 QMetaType::registerNormalizedTypedef(normalizedTypeName, metaType);
1214 QtPrivate::SequentialContainerTransformationHelper<T>::registerConverter();
1215 QtPrivate::SequentialContainerTransformationHelper<T>::registerMutableView();
1216 QtPrivate::AssociativeContainerTransformationHelper<T>::registerConverter();
1217 QtPrivate::AssociativeContainerTransformationHelper<T>::registerMutableView();
1218 QtPrivate::MetaTypePairHelper<T>::registerConverter();
1219 QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter();
1220 }
1221
1222 return id;
1223}
1224
1225template <typename T>
1226int qRegisterMetaType(const char *typeName)
1227{
1228#ifdef QT_NO_QOBJECT
1229 QT_PREPEND_NAMESPACE(QByteArray) normalizedTypeName = typeName;
1230#else
1231 QT_PREPEND_NAMESPACE(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName);
1232#endif
1233 return qRegisterNormalizedMetaType<T>(normalizedTypeName);
1234}
1235
1236template <typename T>
1237inline constexpr int qMetaTypeId()
1238{
1239 if constexpr (bool(QMetaTypeId2<T>::IsBuiltIn)) {
1240 return QMetaTypeId2<T>::MetaType;
1241 } else {
1242 return QMetaType::fromType<T>().id();
1243 }
1244}
1245
1246template <typename T>
1247inline constexpr int qRegisterMetaType()
1248{
1249 int id = qMetaTypeId<T>();
1250 return id;
1251}
1252
1253#ifndef QT_NO_QOBJECT
1254template <typename T>
1255struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
1256{
1257 enum {
1258 Defined = 1
1259 };
1260
1261 static int qt_metatype_id()
1262 {
1263 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1264 if (const int id = metatype_id.loadAcquire())
1265 return id;
1266 const char *const cName = T::staticMetaObject.className();
1267 QByteArray typeName;
1268 typeName.reserve(int(strlen(cName)) + 1);
1269 typeName.append(cName).append('*');
1270 const int newId = qRegisterNormalizedMetaType<T *>(typeName);
1271 metatype_id.storeRelease(newId);
1272 return newId;
1273 }
1274};
1275
1276template <typename T>
1277struct QMetaTypeIdQObject<T, QMetaType::IsGadget>
1278{
1279 enum {
1280 Defined = std::is_default_constructible<T>::value
1281 };
1282
1283 static int qt_metatype_id()
1284 {
1285 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1286 if (const int id = metatype_id.loadAcquire())
1287 return id;
1288 const char *const cName = T::staticMetaObject.className();
1289 const int newId = qRegisterNormalizedMetaType<T>(cName);
1290 metatype_id.storeRelease(newId);
1291 return newId;
1292 }
1293};
1294
1295template <typename T>
1296struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget>
1297{
1298 enum {
1299 Defined = 1
1300 };
1301
1302 static int qt_metatype_id()
1303 {
1304 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1305 if (const int id = metatype_id.loadAcquire())
1306 return id;
1307 const char *const cName = T::staticMetaObject.className();
1308 QByteArray typeName;
1309 typeName.reserve(int(strlen(cName)) + 1);
1310 typeName.append(cName).append('*');
1311 const int newId = qRegisterNormalizedMetaType<T *>(typeName);
1312 metatype_id.storeRelease(newId);
1313 return newId;
1314 }
1315};
1316
1317template <typename T>
1318struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
1319{
1320 enum {
1321 Defined = 1
1322 };
1323
1324 static int qt_metatype_id()
1325 {
1326 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1327 if (const int id = metatype_id.loadAcquire())
1328 return id;
1329 const char *eName = qt_getEnumName(T());
1330 const char *cName = qt_getEnumMetaObject(T())->className();
1331 QByteArray typeName;
1332 typeName.reserve(int(strlen(cName) + 2 + strlen(eName)));
1333 typeName.append(cName).append("::").append(eName);
1334 const int newId = qRegisterNormalizedMetaType<T>(typeName);
1335 metatype_id.storeRelease(newId);
1336 return newId;
1337 }
1338};
1339#endif
1340
1341#define Q_DECLARE_OPAQUE_POINTER(POINTER) \
1342 QT_BEGIN_NAMESPACE namespace QtPrivate { \
1343 template <> \
1344 struct IsPointerToTypeDerivedFromQObject<POINTER > \
1345 { \
1346 enum { Value = false }; \
1347 }; \
1348 } QT_END_NAMESPACE \
1349 /**/
1350
1351#ifndef Q_MOC_RUN
1352#define Q_DECLARE_METATYPE(TYPE) Q_DECLARE_METATYPE_IMPL(TYPE)
1353#define Q_DECLARE_METATYPE_IMPL(TYPE) \
1354 QT_BEGIN_NAMESPACE \
1355 template <> \
1356 struct QMetaTypeId< TYPE > \
1357 { \
1358 enum { Defined = 1 }; \
1359 static int qt_metatype_id() \
1360 { \
1361 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1362 if (const int id = metatype_id.loadAcquire()) \
1363 return id; \
1364 const int newId = qRegisterMetaType< TYPE >(#TYPE); \
1365 metatype_id.storeRelease(newId); \
1366 return newId; \
1367 } \
1368 }; \
1369 QT_END_NAMESPACE
1370#endif // Q_MOC_RUN
1371
1372#define Q_DECLARE_BUILTIN_METATYPE(TYPE, METATYPEID, NAME) \
1373 QT_BEGIN_NAMESPACE \
1374 template<> struct QMetaTypeId2<NAME> \
1375 { \
1376 using NameAsArrayType = std::array<char, sizeof(#NAME)>; \
1377 enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID }; \
1378 static inline constexpr int qt_metatype_id() { return METATYPEID; } \
1379 static constexpr NameAsArrayType nameAsArray = { #NAME }; \
1380 }; \
1381 QT_END_NAMESPACE
1382
1383#define QT_FORWARD_DECLARE_STATIC_TYPES_ITER(TypeName, TypeId, Name) \
1384 class Name;
1385
1386QT_FOR_EACH_STATIC_CORE_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
1387QT_FOR_EACH_STATIC_GUI_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
1388QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
1389
1390#undef QT_FORWARD_DECLARE_STATIC_TYPES_ITER
1391
1392#define Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE) \
1393QT_BEGIN_NAMESPACE \
1394template <typename T> \
1395struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
1396{ \
1397 enum { \
1398 Defined = QMetaTypeId2<T>::Defined \
1399 }; \
1400 static int qt_metatype_id() \
1401 { \
1402 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1403 if (const int id = metatype_id.loadRelaxed()) \
1404 return id; \
1405 const char *tName = QMetaType::fromType<T>().name(); \
1406 Q_ASSERT(tName); \
1407 const int tNameLen = int(qstrlen(tName)); \
1408 QByteArray typeName; \
1409 typeName.reserve(int(sizeof(#SINGLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + 1); \
1410 typeName.append(#SINGLE_ARG_TEMPLATE, int(sizeof(#SINGLE_ARG_TEMPLATE)) - 1) \
1411 .append('<').append(tName, tNameLen); \
1412 typeName.append('>'); \
1413 const int newId = qRegisterNormalizedMetaType< SINGLE_ARG_TEMPLATE<T> >(typeName); \
1414 metatype_id.storeRelease(newId); \
1415 return newId; \
1416 } \
1417}; \
1418namespace QtPrivate { \
1419template<typename T> \
1420struct IsSequentialContainer<SINGLE_ARG_TEMPLATE<T> > \
1421{ \
1422 enum { Value = true }; \
1423}; \
1424} \
1425QT_END_NAMESPACE
1426
1427#define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \
1428QT_BEGIN_NAMESPACE \
1429template<typename T, typename U> \
1430struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \
1431{ \
1432 enum { \
1433 Defined = QMetaTypeId2<T>::Defined && QMetaTypeId2<U>::Defined \
1434 }; \
1435 static int qt_metatype_id() \
1436 { \
1437 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1438 if (const int id = metatype_id.loadAcquire()) \
1439 return id; \
1440 const char *tName = QMetaType::fromType<T>().name(); \
1441 const char *uName = QMetaType::fromType<U>().name(); \
1442 Q_ASSERT(tName); \
1443 Q_ASSERT(uName); \
1444 const int tNameLen = int(qstrlen(tName)); \
1445 const int uNameLen = int(qstrlen(uName)); \
1446 QByteArray typeName; \
1447 typeName.reserve(int(sizeof(#DOUBLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \
1448 typeName.append(#DOUBLE_ARG_TEMPLATE, int(sizeof(#DOUBLE_ARG_TEMPLATE)) - 1) \
1449 .append('<').append(tName, tNameLen).append(',').append(uName, uNameLen); \
1450 typeName.append('>'); \
1451 const int newId = qRegisterNormalizedMetaType< DOUBLE_ARG_TEMPLATE<T, U> >(typeName); \
1452 metatype_id.storeRelease(newId); \
1453 return newId; \
1454 } \
1455}; \
1456QT_END_NAMESPACE
1457
1458namespace QtPrivate {
1459
1460template<typename T, bool /* isSharedPointerToQObjectDerived */ = false>
1461struct SharedPointerMetaTypeIdHelper
1462{
1463 enum {
1464 Defined = 0
1465 };
1466 static int qt_metatype_id()
1467 {
1468 return -1;
1469 }
1470};
1471
1472}
1473
1474#define Q_DECLARE_SMART_POINTER_METATYPE(SMART_POINTER) \
1475QT_BEGIN_NAMESPACE \
1476namespace QtPrivate { \
1477template<typename T> \
1478struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
1479{ \
1480 enum { \
1481 Defined = 1 \
1482 }; \
1483 static int qt_metatype_id() \
1484 { \
1485 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1486 if (const int id = metatype_id.loadAcquire()) \
1487 return id; \
1488 const char * const cName = T::staticMetaObject.className(); \
1489 QByteArray typeName; \
1490 typeName.reserve(int(sizeof(#SMART_POINTER) + 1 + strlen(cName) + 1)); \
1491 typeName.append(#SMART_POINTER, int(sizeof(#SMART_POINTER)) - 1) \
1492 .append('<').append(cName).append('>'); \
1493 const int newId = qRegisterNormalizedMetaType< SMART_POINTER<T> >(typeName); \
1494 metatype_id.storeRelease(newId); \
1495 return newId; \
1496 } \
1497}; \
1498template<typename T> \
1499struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \
1500 typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> \
1501{ \
1502 static bool registerConverter() \
1503 { \
1504 const QMetaType to = QMetaType(QMetaType::QObjectStar); \
1505 if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<SMART_POINTER<T>>(), to)) { \
1506 QtPrivate::QSmartPointerConvertFunctor<SMART_POINTER<T> > o; \
1507 return QMetaType::registerConverter<SMART_POINTER<T>, QObject*>(o); \
1508 } \
1509 return true; \
1510 } \
1511}; \
1512} \
1513template <typename T> \
1514struct QMetaTypeId< SMART_POINTER<T> > \
1515 : QtPrivate::SharedPointerMetaTypeIdHelper< SMART_POINTER<T>, \
1516 QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value> \
1517{ \
1518};\
1519QT_END_NAMESPACE
1520
1521#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER(TEMPLATENAME) \
1522 Q_DECLARE_METATYPE_TEMPLATE_1ARG(TEMPLATENAME)
1523
1524QT_END_NAMESPACE
1525
1526QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER)
1527
1528#undef Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER
1529
1530#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE Q_DECLARE_METATYPE_TEMPLATE_1ARG
1531
1532Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::vector)
1533Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::list)
1534
1535#define Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(TEMPLATENAME) \
1536 QT_BEGIN_NAMESPACE \
1537 namespace QtPrivate { \
1538 template<typename T, typename U> \
1539 struct IsAssociativeContainer<TEMPLATENAME<T, U> > \
1540 { \
1541 enum { Value = true }; \
1542 }; \
1543 } \
1544 QT_END_NAMESPACE \
1545 Q_DECLARE_METATYPE_TEMPLATE_2ARG(TEMPLATENAME)
1546
1547Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QHash)
1548Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QMap)
1549Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::map)
1550
1551Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::pair)
1552
1553#define Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER(TEMPLATENAME) \
1554 Q_DECLARE_SMART_POINTER_METATYPE(TEMPLATENAME)
1555
1556QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER)
1557
1558QT_BEGIN_NAMESPACE
1559
1560#undef Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER
1561
1562QT_END_NAMESPACE
1563
1564QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
1565
1566Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl)
1567
1568QT_BEGIN_NAMESPACE
1569
1570template <typename T>
1571inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter()
1572{
1573 const QMetaType to = QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
1574 if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
1575 QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o;
1576 return QMetaType::registerConverter<T, QtMetaTypePrivate::QPairVariantInterfaceImpl>(o);
1577 }
1578 return true;
1579}
1580
1581namespace QtPrivate {
1582
1583template<typename From>
1584struct QSequentialIterableConvertFunctor
1585{
1586 QIterable<QMetaSequence> operator()(const From &f) const
1587 {
1588 return QIterable<QMetaSequence>(QMetaSequence::fromContainer<From>(), &f);
1589 }
1590};
1591
1592template<typename From>
1593struct QSequentialIterableMutableViewFunctor
1594{
1595 QIterable<QMetaSequence> operator()(From &f) const
1596 {
1597 return QIterable<QMetaSequence>(QMetaSequence::fromContainer<From>(), &f);
1598 }
1599};
1600
1601template<typename T>
1602struct SequentialValueTypeIsMetaType<T, true>
1603{
1604 static bool registerConverter()
1605 {
1606 const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
1607 if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
1608 QSequentialIterableConvertFunctor<T> o;
1609 return QMetaType::registerConverter<T, QIterable<QMetaSequence>>(o);
1610 }
1611 return true;
1612 }
1613
1614 static bool registerMutableView()
1615 {
1616 const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
1617 if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) {
1618 QSequentialIterableMutableViewFunctor<T> o;
1619 return QMetaType::registerMutableView<T, QIterable<QMetaSequence>>(o);
1620 }
1621 return true;
1622 }
1623};
1624
1625template<typename From>
1626struct QAssociativeIterableConvertFunctor
1627{
1628 QIterable<QMetaAssociation> operator()(const From &f) const
1629 {
1630 return QIterable<QMetaAssociation>(QMetaAssociation::fromContainer<From>(), &f);
1631 }
1632};
1633
1634template<typename From>
1635struct QAssociativeIterableMutableViewFunctor
1636{
1637 QIterable<QMetaAssociation> operator()(From &f) const
1638 {
1639 return QIterable<QMetaAssociation>(QMetaAssociation::fromContainer<From>(), &f);
1640 }
1641};
1642
1643// Mapped type can be omitted, for example in case of a set.
1644// However, if it is available, we want to instantiate the metatype here.
1645template<typename T>
1646struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T>
1647{
1648 static bool registerConverter()
1649 {
1650 const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
1651 if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
1652 QAssociativeIterableConvertFunctor<T> o;
1653 return QMetaType::registerConverter<T, QIterable<QMetaAssociation>>(o);
1654 }
1655 return true;
1656 }
1657
1658 static bool registerMutableView()
1659 {
1660 const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
1661 if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) {
1662 QAssociativeIterableMutableViewFunctor<T> o;
1663 return QMetaType::registerMutableView<T, QIterable<QMetaAssociation>>(o);
1664 }
1665 return true;
1666 }
1667};
1668
1669struct QTypeNormalizer
1670{
1671 char *output;
1672 int len = 0;
1673 char last = 0;
1674
1675private:
1676 static constexpr bool is_ident_char(char s)
1677 {
1678 return ((s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || (s >= '0' && s <= '9')
1679 || s == '_');
1680 }
1681 static constexpr bool is_space(char s) { return (s == ' ' || s == '\t' || s == '\n'); }
1682 static constexpr bool is_number(char s) { return s >= '0' && s <= '9'; }
1683 static constexpr bool starts_with_token(const char *b, const char *e, const char *token,
1684 bool msvcKw = false)
1685 {
1686 while (b != e && *token && *b == *token) {
1687 b++;
1688 token++;
1689 }
1690 if (*token)
1691 return false;
1692#ifdef Q_CC_MSVC
1693 /// On MSVC, keywords like class or struct are not separated with spaces in constexpr
1694 /// context
1695 if (msvcKw)
1696 return true;
1697#endif
1698 Q_UNUSED(msvcKw);
1699 return b == e || !is_ident_char(*b);
1700 }
1701 static constexpr bool skipToken(const char *&x, const char *e, const char *token,
1702 bool msvcKw = false)
1703 {
1704 if (!starts_with_token(x, e, token, msvcKw))
1705 return false;
1706 while (*token++)
1707 x++;
1708 while (x != e && is_space(*x))
1709 x++;
1710 return true;
1711 }
1712 static constexpr const char *skipString(const char *x, const char *e)
1713 {
1714 char delim = *x;
1715 x++;
1716 while (x != e && *x != delim) {
1717 if (*x == '\\') {
1718 x++;
1719 if (x == e)
1720 return e;
1721 }
1722 x++;
1723 }
1724 if (x != e)
1725 x++;
1726 return x;
1727 };
1728 static constexpr const char *skipTemplate(const char *x, const char *e, bool stopAtComa = false)
1729 {
1730 int scopeDepth = 0;
1731 int templateDepth = 0;
1732 while (x != e) {
1733 switch (*x) {
1734 case '<':
1735 if (!scopeDepth)
1736 templateDepth++;
1737 break;
1738 case ',':
1739 if (stopAtComa && !scopeDepth && !templateDepth)
1740 return x;
1741 break;
1742 case '>':
1743 if (!scopeDepth)
1744 if (--templateDepth < 0)
1745 return x;
1746 break;
1747 case '(':
1748 case '[':
1749 case '{':
1750 scopeDepth++;
1751 break;
1752 case '}':
1753 case ']':
1754 case ')':
1755 scopeDepth--;
1756 break;
1757 case '\'':
1758 if (is_number(x[-1]))
1759 break;
1760 Q_FALLTHROUGH();
1761 case '\"':
1762 x = skipString(x, e);
1763 continue;
1764 }
1765 x++;
1766 }
1767 return x;
1768 };
1769
1770 constexpr void append(char x)
1771 {
1772 last = x;
1773 len++;
1774 if (output)
1775 *output++ = x;
1776 }
1777
1778 constexpr void replaceLast(char x)
1779 {
1780 last = x;
1781 if (output)
1782 *(output - 1) = x;
1783 }
1784
1785 constexpr void appendStr(const char *x)
1786 {
1787 while (*x)
1788 append(*x++);
1789 };
1790
1791 constexpr void normalizeIntegerTypes(const char *&begin, const char *end)
1792 {
1793 int numLong = 0;
1794 int numSigned = 0;
1795 int numUnsigned = 0;
1796 int numInt = 0;
1797 int numShort = 0;
1798 int numChar = 0;
1799 while (begin < end) {
1800 if (skipToken(begin, end, "long")) {
1801 numLong++;
1802 continue;
1803 }
1804 if (skipToken(begin, end, "int")) {
1805 numInt++;
1806 continue;
1807 }
1808 if (skipToken(begin, end, "short")) {
1809 numShort++;
1810 continue;
1811 }
1812 if (skipToken(begin, end, "unsigned")) {
1813 numUnsigned++;
1814 continue;
1815 }
1816 if (skipToken(begin, end, "signed")) {
1817 numSigned++;
1818 continue;
1819 }
1820 if (skipToken(begin, end, "char")) {
1821 numChar++;
1822 continue;
1823 }
1824#ifdef Q_CC_MSVC
1825 if (skipToken(begin, end, "__int64")) {
1826 numLong = 2;
1827 continue;
1828 }
1829#endif
1830 break;
1831 }
1832 if (numLong == 2)
1833 append('q'); // q(u)longlong
1834 if (numSigned && numChar)
1835 appendStr("signed ");
1836 else if (numUnsigned)
1837 appendStr("u");
1838 if (numChar)
1839 appendStr("char");
1840 else if (numShort)
1841 appendStr("short");
1842 else if (numLong == 1)
1843 appendStr("long");
1844 else if (numLong == 2)
1845 appendStr("longlong");
1846 else if (numUnsigned || numSigned || numInt)
1847 appendStr("int");
1848 }
1849
1850 constexpr void skipStructClassOrEnum(const char *&begin, const char *end)
1851 {
1852 // discard 'struct', 'class', and 'enum'; they are optional
1853 // and we don't want them in the normalized signature
1854 skipToken(begin, end, "struct", true) || skipToken(begin, end, "class", true)
1855 || skipToken(begin, end, "enum", true);
1856 }
1857
1858 constexpr void skipQtNamespace(const char *&begin, const char *end)
1859 {
1860#ifdef QT_NAMESPACE
1861 const char *nsbeg = begin;
1862 if (skipToken(nsbeg, end, QT_STRINGIFY(QT_NAMESPACE)) && nsbeg + 2 < end && nsbeg[0] == ':'
1863 && nsbeg[1] == ':') {
1864 begin = nsbeg + 2;
1865 while (begin != end && is_space(*begin))
1866 begin++;
1867 }
1868#else
1869 Q_UNUSED(begin);
1870 Q_UNUSED(end);
1871#endif
1872 }
1873
1874public:
1875#ifndef Q_CC_MSVC
1876 // this is much simpler than the full type normalization below
1877 // the reason is that the signature returned by Q_FUNC_INFO is already
1878 // normalized to the largest degree, and we need to do only small adjustments
1879 constexpr int normalizeTypeFromSignature(const char *begin, const char *end)
1880 {
1881 while (begin < end) {
1882 if (*begin == ' ') {
1883 if (last == ',' || last == '>' || last == '<' || last == '*' || last == '&') {
1884 ++begin;
1885 continue;
1886 }
1887 }
1888 if (last == ' ') {
1889 if (*begin == '*' || *begin == '&') {
1890 replaceLast(*begin);
1891 ++begin;
1892 continue;
1893 }
1894 }
1895 if (!is_ident_char(last)) {
1896 skipStructClassOrEnum(begin, end);
1897 if (begin == end)
1898 break;
1899
1900 skipQtNamespace(begin, end);
1901 if (begin == end)
1902 break;
1903
1904 normalizeIntegerTypes(begin, end);
1905 if (begin == end)
1906 break;
1907 }
1908 append(*begin);
1909 ++begin;
1910 }
1911 return len;
1912 }
1913#else
1914 // MSVC needs the full normalization, as it puts the const in a different
1915 // place than we expect
1916 constexpr int normalizeTypeFromSignature(const char *begin, const char *end)
1917 { return normalizeType(begin, end); }
1918#endif
1919
1920 constexpr int normalizeType(const char *begin, const char *end, bool adjustConst = true)
1921 {
1922 // Trim spaces
1923 while (begin != end && is_space(*begin))
1924 begin++;
1925 while (begin != end && is_space(*(end - 1)))
1926 end--;
1927
1928 // Convert 'char const *' into 'const char *'. Start at index 1,
1929 // not 0, because 'const char *' is already OK.
1930 const char *cst = begin + 1;
1931 if (*begin == '\'' || *begin == '"')
1932 cst = skipString(begin, end);
1933 bool seenStar = false;
1934 bool hasMiddleConst = false;
1935 while (cst < end) {
1936 if (*cst == '\"' || (*cst == '\'' && !is_number(cst[-1]))) {
1937 cst = skipString(cst, end);
1938 if (cst == end)
1939 break;
1940 }
1941
1942 // We mustn't convert 'char * const *' into 'const char **'
1943 // and we must beware of 'Bar<const Bla>'.
1944 if (*cst == '&' || *cst == '*' || *cst == '[') {
1945 seenStar = *cst != '&' || cst != (end - 1);
1946 break;
1947 }
1948 if (*cst == '<') {
1949 cst = skipTemplate(cst + 1, end);
1950 if (cst == end)
1951 break;
1952 }
1953 cst++;
1954 const char *skipedCst = cst;
1955 if (!is_ident_char(*(cst - 1)) && skipToken(skipedCst, end, "const")) {
1956 const char *testEnd = end;
1957 while (skipedCst < testEnd--) {
1958 if (*testEnd == '*' || *testEnd == '['
1959 || (*testEnd == '&' && testEnd != (end - 1))) {
1960 seenStar = true;
1961 break;
1962 }
1963 if (*testEnd == '>')
1964 break;
1965 }
1966 if (adjustConst && !seenStar) {
1967 if (*(end - 1) == '&')
1968 end--;
1969 } else {
1970 appendStr("const ");
1971 }
1972 normalizeType(begin, cst, false);
1973 begin = skipedCst;
1974 hasMiddleConst = true;
1975 break;
1976 }
1977 }
1978 if (skipToken(begin, end, "const")) {
1979 if (adjustConst && !seenStar) {
1980 if (*(end - 1) == '&')
1981 end--;
1982 } else {
1983 appendStr("const ");
1984 }
1985 }
1986 if (seenStar && adjustConst) {
1987 const char *e = end;
1988 if (*(end - 1) == '&' && *(end - 2) != '&')
1989 e--;
1990 while (begin != e && is_space(*(e - 1)))
1991 e--;
1992 const char *token = "tsnoc"; // 'const' reverse, to check if it ends with const
1993 while (*token && begin != e && *(--e) == *token++)
1994 ;
1995 if (!*token && begin != e && !is_ident_char(*(e - 1))) {
1996 while (begin != e && is_space(*(e - 1)))
1997 e--;
1998 end = e;
1999 }
2000 }
2001
2002 skipStructClassOrEnum(begin, end);
2003 skipQtNamespace(begin, end);
2004
2005 if (skipToken(begin, end, "QVector")) {
2006 // Replace QVector by QList
2007 appendStr("QList");
2008 }
2009
2010 if (skipToken(begin, end, "QPair")) {
2011 // replace QPair by std::pair
2012 appendStr("std::pair");
2013 }
2014
2015 if (!hasMiddleConst)
2016 // Normalize the integer types
2017 normalizeIntegerTypes(begin, end);
2018
2019 bool spaceSkiped = true;
2020 while (begin != end) {
2021 char c = *begin++;
2022 if (is_space(c)) {
2023 spaceSkiped = true;
2024 } else if ((c == '\'' && !is_number(last)) || c == '\"') {
2025 begin--;
2026 auto x = skipString(begin, end);
2027 while (begin < x)
2028 append(*begin++);
2029 } else {
2030 if (spaceSkiped && is_ident_char(last) && is_ident_char(c))
2031 append(' ');
2032 append(c);
2033 spaceSkiped = false;
2034 if (c == '<') {
2035 do {
2036 // template recursion
2037 const char *tpl = skipTemplate(begin, end, true);
2038 normalizeType(begin, tpl, false);
2039 if (tpl == end)
2040 return len;
2041 append(*tpl);
2042 begin = tpl;
2043 } while (*begin++ == ',');
2044 }
2045 }
2046 }
2047 return len;
2048 }
2049};
2050
2051// Normalize the type between begin and end, and store the data in the output. Returns the length.
2052// The idea is to first run this function with nullptr as output to allocate the output with the
2053// size
2054constexpr int qNormalizeType(const char *begin, const char *end, char *output)
2055{
2056 return QTypeNormalizer { output }.normalizeType(begin, end);
2057}
2058
2059template<typename T>
2060struct is_std_pair : std::false_type {};
2061
2062template <typename T1_, typename T2_>
2063struct is_std_pair<std::pair<T1_, T2_>> : std::true_type {
2064 using T1 = T1_;
2065 using T2 = T2_;
2066};
2067
2068template<typename T>
2069constexpr auto typenameHelper()
2070{
2071 if constexpr (is_std_pair<T>::value) {
2072 using T1 = typename is_std_pair<T>::T1;
2073 using T2 = typename is_std_pair<T>::T2;
2074 std::remove_const_t<std::conditional_t<bool (QMetaTypeId2<T1>::IsBuiltIn), typename QMetaTypeId2<T1>::NameAsArrayType, decltype(typenameHelper<T1>())>> t1Name {};
2075 std::remove_const_t<std::conditional_t<bool (QMetaTypeId2<T2>::IsBuiltIn), typename QMetaTypeId2<T2>::NameAsArrayType, decltype(typenameHelper<T2>())>> t2Name {};
2076 if constexpr (bool (QMetaTypeId2<T1>::IsBuiltIn) ) {
2077 t1Name = QMetaTypeId2<T1>::nameAsArray;
2078 } else {
2079 t1Name = typenameHelper<T1>();
2080 }
2081 if constexpr (bool(QMetaTypeId2<T2>::IsBuiltIn)) {
2082 t2Name = QMetaTypeId2<T2>::nameAsArray;
2083 } else {
2084 t2Name = typenameHelper<T2>();
2085 }
2086 constexpr auto nonTypeDependentLen = sizeof("std::pair<,>");
2087 constexpr auto t1Len = t1Name.size() - 1;
2088 constexpr auto t2Len = t2Name.size() - 1;
2089 constexpr auto length = nonTypeDependentLen + t1Len + t2Len;
2090 std::array<char, length + 1> result {};
2091 constexpr auto prefix = "std::pair<";
2092 int currentLength = 0;
2093 for (; currentLength < int(sizeof("std::pair<") - 1); ++currentLength)
2094 result[currentLength] = prefix[currentLength];
2095 for (int i = 0; i < int(t1Len); ++currentLength, ++i)
2096 result[currentLength] = t1Name[i];
2097 result[currentLength++] = ',';
2098 for (int i = 0; i < int(t2Len); ++currentLength, ++i)
2099 result[currentLength] = t2Name[i];
2100 result[currentLength++] = '>';
2101 result[currentLength++] = '\0';
2102 return result;
2103 } else {
2104 constexpr auto prefix = sizeof(
2105#ifdef QT_NAMESPACE
2106 QT_STRINGIFY(QT_NAMESPACE) "::"
2107#endif
2108#ifdef Q_CC_MSVC
2109 "auto __cdecl QtPrivate::typenameHelper<"
2110#elif defined(Q_CC_CLANG)
2111 "auto QtPrivate::typenameHelper() [T = "
2112#elif defined(Q_CC_GHS)
2113 "auto QtPrivate::typenameHelper<T>() [with T = "
2114#else
2115 "constexpr auto QtPrivate::typenameHelper() [with T = "
2116#endif
2117 ) - 1;
2118#ifdef Q_CC_MSVC
2119 constexpr int suffix = sizeof(">(void)");
2120#else
2121 constexpr int suffix = sizeof("]");
2122#endif
2123
2124#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) && Q_CC_GNU < 804)
2125 auto func = Q_FUNC_INFO;
2126 const char *begin = func + prefix;
2127 const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
2128 // This is an upper bound of the size since the normalized signature should always be smaller
2129 constexpr int len = sizeof(Q_FUNC_INFO) - suffix - prefix;
2130#else
2131 constexpr auto func = Q_FUNC_INFO;
2132 constexpr const char *begin = func + prefix;
2133 constexpr const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
2134 constexpr int len = QTypeNormalizer{ nullptr }.normalizeTypeFromSignature(begin, end);
2135#endif
2136 std::array<char, len + 1> result {};
2137 QTypeNormalizer{ result.data() }.normalizeTypeFromSignature(begin, end);
2138 return result;
2139 }
2140}
2141
2142template<typename T, typename = void>
2143struct BuiltinMetaType : std::integral_constant<int, 0>
2144{
2145};
2146template<typename T>
2147struct BuiltinMetaType<T, std::enable_if_t<QMetaTypeId2<T>::IsBuiltIn>>
2148 : std::integral_constant<int, QMetaTypeId2<T>::MetaType>
2149{
2150};
2151
2152template<typename T, bool = (QTypeTraits::has_operator_equal_v<T> && !std::is_pointer_v<T>)>
2153struct QEqualityOperatorForType
2154{
2155QT_WARNING_PUSH
2156QT_WARNING_DISABLE_FLOAT_COMPARE
2157 static bool equals(const QMetaTypeInterface *, const void *a, const void *b)
2158 { return *reinterpret_cast<const T *>(a) == *reinterpret_cast<const T *>(b); }
2159QT_WARNING_POP
2160};
2161
2162template<typename T>
2163struct QEqualityOperatorForType <T, false>
2164{
2165 static constexpr QMetaTypeInterface::EqualsFn equals = nullptr;
2166};
2167
2168template<typename T, bool = (QTypeTraits::has_operator_less_than_v<T> && !std::is_pointer_v<T>)>
2169struct QLessThanOperatorForType
2170{
2171 static bool lessThan(const QMetaTypeInterface *, const void *a, const void *b)
2172 { return *reinterpret_cast<const T *>(a) < *reinterpret_cast<const T *>(b); }
2173};
2174
2175template<typename T>
2176struct QLessThanOperatorForType <T, false>
2177{
2178 static constexpr QMetaTypeInterface::LessThanFn lessThan = nullptr;
2179};
2180
2181template<typename T, bool = (QTypeTraits::has_ostream_operator_v<QDebug, T> && !std::is_pointer_v<T>)>
2182struct QDebugStreamOperatorForType
2183{
2184 static void debugStream(const QMetaTypeInterface *, QDebug &dbg, const void *a)
2185 { dbg << *reinterpret_cast<const T *>(a); }
2186};
2187
2188template<typename T>
2189struct QDebugStreamOperatorForType <T, false>
2190{
2191 static constexpr QMetaTypeInterface::DebugStreamFn debugStream = nullptr;
2192};
2193
2194template<typename T, bool = QTypeTraits::has_stream_operator_v<QDataStream, T>>
2195struct QDataStreamOperatorForType
2196{
2197 static void dataStreamOut(const QMetaTypeInterface *, QDataStream &ds, const void *a)
2198 { ds << *reinterpret_cast<const T *>(a); }
2199 static void dataStreamIn(const QMetaTypeInterface *, QDataStream &ds, void *a)
2200 { ds >> *reinterpret_cast<T *>(a); }
2201};
2202
2203template<typename T>
2204struct QDataStreamOperatorForType <T, false>
2205{
2206 static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
2207 static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
2208};
2209
2210template<typename S>
2211class QMetaTypeForType
2212{
2213public:
2214 static constexpr decltype(typenameHelper<S>()) name = typenameHelper<S>();
2215
2216 static constexpr QMetaTypeInterface::DefaultCtrFn getDefaultCtr()
2217 {
2218 if constexpr (std::is_default_constructible_v<S>) {
2219 return [](const QMetaTypeInterface *, void *addr) { new (addr) S(); };
2220 } else {
2221 return nullptr;
2222 }
2223 }
2224
2225 static constexpr QMetaTypeInterface::CopyCtrFn getCopyCtr()
2226 {
2227 if constexpr (std::is_copy_constructible_v<S>) {
2228 return [](const QMetaTypeInterface *, void *addr, const void *other) {
2229 new (addr) S(*reinterpret_cast<const S *>(other));
2230 };
2231 } else {
2232 return nullptr;
2233 }
2234 }
2235
2236 static constexpr QMetaTypeInterface::MoveCtrFn getMoveCtr()
2237 {
2238 if constexpr (std::is_move_constructible_v<S>) {
2239 return [](const QMetaTypeInterface *, void *addr, void *other) {
2240 new (addr) S(std::move(*reinterpret_cast<S *>(other)));
2241 };
2242 } else {
2243 return nullptr;
2244 }
2245 }
2246
2247 static constexpr QMetaTypeInterface::DtorFn getDtor()
2248 {
2249 if constexpr (std::is_destructible_v<S> && !std::is_trivially_destructible_v<S>)
2250 return [](const QMetaTypeInterface *, void *addr) {
2251 reinterpret_cast<S *>(addr)->~S();
2252 };
2253 else
2254 return nullptr;
2255 }
2256
2257 static constexpr QMetaTypeInterface::LegacyRegisterOp getLegacyRegister()
2258 {
2259 if constexpr (QMetaTypeId2<S>::Defined && !QMetaTypeId2<S>::IsBuiltIn) {
2260 return []() { QMetaTypeId2<S>::qt_metatype_id(); };
2261 } else {
2262 return nullptr;
2263 }
2264 }
2265
2266 static constexpr const char *getName()
2267 {
2268 if constexpr (bool(QMetaTypeId2<S>::IsBuiltIn)) {
2269 return QMetaTypeId2<S>::nameAsArray.data();
2270 } else {
2271 return name.data();
2272 }
2273 }
2274};
2275
2276template<typename T>
2277struct QMetaTypeInterfaceWrapper
2278{
2279 static inline constexpr const QMetaTypeInterface metaType = {
2280 /*.revision=*/ 0,
2281 /*.alignment=*/ alignof(T),
2282 /*.size=*/ sizeof(T),
2283 /*.flags=*/ QMetaTypeTypeFlags<T>::Flags,
2284 /*.typeId=*/ BuiltinMetaType<T>::value,
2285 /*.metaObjectFn=*/ MetaObjectForType<T>::metaObjectFunction,
2286 /*.name=*/ QMetaTypeForType<T>::getName(),
2287 /*.defaultCtr=*/ QMetaTypeForType<T>::getDefaultCtr(),
2288 /*.copyCtr=*/ QMetaTypeForType<T>::getCopyCtr(),
2289 /*.moveCtr=*/ QMetaTypeForType<T>::getMoveCtr(),
2290 /*.dtor=*/ QMetaTypeForType<T>::getDtor(),
2291 /*.equals=*/ QEqualityOperatorForType<T>::equals,
2292 /*.lessThan=*/ QLessThanOperatorForType<T>::lessThan,
2293 /*.debugStream=*/ QDebugStreamOperatorForType<T>::debugStream,
2294 /*.dataStreamOut=*/ QDataStreamOperatorForType<T>::dataStreamOut,
2295 /*.dataStreamIn=*/ QDataStreamOperatorForType<T>::dataStreamIn,
2296 /*.legacyRegisterOp=*/ QMetaTypeForType<T>::getLegacyRegister()
2297 };
2298};
2299
2300
2301template<>
2302class QMetaTypeInterfaceWrapper<void>
2303{
2304public:
2305 static constexpr QMetaTypeInterface metaType =
2306 {
2307 /*.revision=*/ 0,
2308 /*.alignment=*/ 0,
2309 /*.size=*/ 0,
2310 /*.flags=*/ 0,
2311 /*.typeId=*/ BuiltinMetaType<void>::value,
2312 /*.metaObjectFn=*/ nullptr,
2313 /*.name=*/ "void",
2314 /*.defaultCtr=*/ nullptr,
2315 /*.copyCtr=*/ nullptr,
2316 /*.moveCtr=*/ nullptr,
2317 /*.dtor=*/ nullptr,
2318 /*.equals=*/ nullptr,
2319 /*.lessThan=*/ nullptr,
2320 /*.debugStream=*/ nullptr,
2321 /*.dataStreamOut=*/ nullptr,
2322 /*.dataStreamIn=*/ nullptr,
2323 /*.legacyRegisterOp=*/ nullptr
2324 };
2325};
2326#undef QT_METATYPE_CONSTEXPRLAMDA
2327
2328#ifndef QT_BOOTSTRAPPED
2329
2330#if !defined(Q_CC_MSVC) || !defined(QT_BUILD_CORE_LIB)
2331#define QT_METATYPE_TEMPLATE_EXPORT Q_CORE_EXPORT
2332#else
2333#define QT_METATYPE_TEMPLATE_EXPORT
2334#endif
2335
2336#define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
2337 extern template class QT_METATYPE_TEMPLATE_EXPORT QMetaTypeForType<Name>;
2338QT_WARNING_PUSH
2339QT_WARNING_DISABLE_GCC("-Wattributes") // false positive because of QMetaTypeForType<void>
2340QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2341QT_WARNING_POP
2342QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2343QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2344QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2345QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2346#undef QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER
2347#undef QT_METATYPE_TEMPLATE_EXPORT
2348#endif
2349
2350template<typename T>
2351constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType()
2352{
2353 using Ty = std::remove_cv_t<std::remove_reference_t<T>>;
2354 return &QMetaTypeInterfaceWrapper<Ty>::metaType;
2355}
2356
2357namespace detail {
2358template<typename T, typename ODR_VIOLATION_PREVENTER>
2359struct is_complete_helper
2360{
2361 template<typename U>
2362 static auto check(U *) -> std::integral_constant<bool, sizeof(U) != 0>;
2363 static auto check(...) -> std::false_type;
2364 using type = decltype(check(static_cast<T *>(nullptr)));
2365};
2366} // namespace detail
2367
2368template <typename T, typename ODR_VIOLATION_PREVENTER>
2369struct is_complete : detail::is_complete_helper<T, ODR_VIOLATION_PREVENTER>::type {};
2370
2371template<typename T>
2372struct qRemovePointerLike
2373{
2374 using type = std::remove_pointer_t<T>;
2375};
2376
2377#define Q_REMOVE_POINTER_LIKE_IMPL(Pointer) \
2378template <typename T> \
2379struct qRemovePointerLike<Pointer<T>> \
2380{ \
2381 using type = T; \
2382};
2383
2384QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_REMOVE_POINTER_LIKE_IMPL)
2385template<typename T>
2386using qRemovePointerLike_t = typename qRemovePointerLike<T>::type;
2387#undef Q_REMOVE_POINTER_LIKE_IMPL
2388
2389template<typename T, typename ForceComplete_>
2390struct TypeAndForceComplete
2391{
2392 using type = T;
2393 using ForceComplete = ForceComplete_;
2394};
2395
2396template<typename Unique, typename TypeCompletePair>
2397constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType()
2398{
2399 using T = typename TypeCompletePair::type;
2400 using ForceComplete = typename TypeCompletePair::ForceComplete;
2401 using Ty = std::remove_cv_t<std::remove_reference_t<T>>;
2402 using Tz = qRemovePointerLike_t<Ty>;
2403 if constexpr (!is_complete<Tz, Unique>::value && !ForceComplete::value) {
2404 return nullptr;
2405 } else {
2406 return &QMetaTypeInterfaceWrapper<Ty>::metaType;
2407 }
2408}
2409
2410} // namespace QtPrivate
2411
2412template<typename T>
2413constexpr QMetaType QMetaType::fromType()
2414{
2415 return QMetaType(QtPrivate::qMetaTypeInterfaceForType<T>());
2416}
2417
2418constexpr qsizetype QMetaType::sizeOf() const
2419{
2420 return d_ptr ? d_ptr->size : 0;
2421}
2422
2423constexpr qsizetype QMetaType::alignOf() const
2424{
2425 return d_ptr ? d_ptr->alignment : 0;
2426}
2427
2428constexpr QMetaType::TypeFlags QMetaType::flags() const
2429{
2430 return d_ptr ? TypeFlags(d_ptr->flags) : TypeFlags{};
2431}
2432
2433constexpr const QMetaObject *QMetaType::metaObject() const
2434{
2435 return d_ptr && d_ptr->metaObjectFn ? d_ptr->metaObjectFn(d_ptr) : nullptr;
2436}
2437
2438template<typename... T>
2439constexpr const QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = {
2440 QtPrivate::qMetaTypeInterfaceForType<T>()...
2441};
2442
2443constexpr const char *QMetaType::name() const
2444{
2445 return d_ptr ? d_ptr->name : nullptr;
2446}
2447
2448template<typename Unique,typename... T>
2449constexpr const QtPrivate::QMetaTypeInterface *const qt_incomplete_metaTypeArray[] = {
2450 QtPrivate::qTryMetaTypeInterfaceForType<Unique, T>()...
2451};
2452
2453QT_END_NAMESPACE
2454
2455#endif // QMETATYPE_H
2456