QMetaType: Provide underlyingType for enums
Currently, Qt assumes that enums always have int as their underlying type (both in QMetaEnum::keyToValue and in the QML engine). This change makes it possible to to retrieve the underlying type from an enum's metaype - or rather, a metatype of an integral type with the same size and signedness. The use cases aobve don't really rely on the exact same type. In most cases, we wouldn't even need the signedness, however that is already available anyway, and it will come in handy once QML supports bigint, and we need to decide whether we should return While it would be possible for individual users of this function to manually query the size and signedness, having a function returning a metatype offers additional convenience - especially in QML, where the conversion APIs generally operate on metatypes. Task-number: QTBUG-27451 Task-number: QTBUG-84055 Task-number: QTBUG-112180 Change-Id: Icf733b42df0ea64017d69f4d94cb7c855d9e3201 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
454b1de22c
commit
e7cb3cb041
@ -2896,6 +2896,59 @@ bool QMetaType::hasRegisteredDataStreamOperators() const
|
||||
return d_ptr && d_ptr->dataStreamIn != nullptr && d_ptr->dataStreamOut != nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.6
|
||||
|
||||
If this metatype represents an enumeration, this method returns a
|
||||
metatype of a numeric class of the same signedness and size as the
|
||||
enums underlying type.
|
||||
If it represents a QFlags type, it returns QMetaType::Int.
|
||||
In all other cases an invalid QMetaType is returned.
|
||||
*/
|
||||
QMetaType QMetaType::underlyingType() const
|
||||
{
|
||||
if (!d_ptr || !(flags() & IsEnumeration))
|
||||
return {};
|
||||
/* QFlags has enumeration set so that's handled here (qint32
|
||||
case), as QFlags uses int as the underlying type
|
||||
Note that we do some approximation here, as we cannot
|
||||
differentiate between different underlying types of the
|
||||
same size and signedness (consider char <-> (un)signed char,
|
||||
int <-> long <-> long long).
|
||||
|
||||
### TODO PENDING: QTBUG-111926 - QFlags supporting >32 bit int
|
||||
*/
|
||||
if (flags() & IsUnsignedEnumeration) {
|
||||
switch (sizeOf()) {
|
||||
case 1:
|
||||
return QMetaType::fromType<quint8>();
|
||||
case 2:
|
||||
return QMetaType::fromType<quint16>();
|
||||
case 4:
|
||||
return QMetaType::fromType<quint32>();
|
||||
case 8:
|
||||
return QMetaType::fromType<quint64>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (sizeOf()) {
|
||||
case 1:
|
||||
return QMetaType::fromType<qint8>();
|
||||
case 2:
|
||||
return QMetaType::fromType<qint16>();
|
||||
case 4:
|
||||
return QMetaType::fromType<qint32>();
|
||||
case 8:
|
||||
return QMetaType::fromType<qint64>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// int128 can be handled above once we have qint128
|
||||
return QMetaType();
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QMetaType::load(QDataStream &stream, int type, void *data)
|
||||
\overload
|
||||
@ -3163,6 +3216,7 @@ QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_TEMPLATE_ITER)
|
||||
QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_TEMPLATE_ITER)
|
||||
QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_TEMPLATE_ITER)
|
||||
QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_TEMPLATE_ITER)
|
||||
|
||||
#undef QT_METATYPE_DECLARE_TEMPLATE_ITER
|
||||
#endif
|
||||
}
|
||||
|
@ -485,6 +485,8 @@ public:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QMetaType underlyingType() const;
|
||||
|
||||
template<typename T>
|
||||
constexpr static QMetaType fromType();
|
||||
static QMetaType fromName(QByteArrayView name);
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <QtCore/qflags.h>
|
||||
|
||||
Q_DECLARE_METATYPE(QMetaType::Type)
|
||||
Q_DECLARE_METATYPE(QPartialOrdering)
|
||||
|
||||
@ -1838,6 +1840,58 @@ void tst_QMetaType::isEnum()
|
||||
QVERIFY((QMetaType(type6).flags() & QMetaType::IsEnumeration) == QMetaType::IsEnumeration);
|
||||
}
|
||||
|
||||
enum E1 : unsigned char {};
|
||||
enum E2 : qlonglong {};
|
||||
enum class E3 : unsigned short {};
|
||||
|
||||
namespace myflags {
|
||||
|
||||
Q_NAMESPACE
|
||||
|
||||
enum Flag1 : int { A, B };
|
||||
enum Flag2 : short { X, Y };
|
||||
|
||||
Q_DECLARE_FLAGS(Flags1, myflags::Flag1);
|
||||
Q_FLAG_NS(Flags1)
|
||||
Q_DECLARE_FLAGS(Flags2, myflags::Flag2);
|
||||
Q_FLAG_NS(Flags2)
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using getUnderlyingTypeNormalized = std::conditional_t<
|
||||
std::is_signed_v<std::underlying_type_t<T>>,
|
||||
typename QIntegerForSize<sizeof(T)>::Signed,
|
||||
typename QIntegerForSize<sizeof(T)>::Unsigned
|
||||
>;
|
||||
|
||||
void tst_QMetaType::underlyingType_data()
|
||||
{
|
||||
QTest::addColumn<QMetaType>("source");
|
||||
QTest::addColumn<QMetaType>("underlying");
|
||||
|
||||
QTest::newRow("invalid") << QMetaType() << QMetaType();
|
||||
QTest::newRow("plain") << QMetaType::fromType<isEnumTest_Enum1>()
|
||||
<< QMetaType::fromType<getUnderlyingTypeNormalized<isEnumTest_Enum1>>();
|
||||
QTest::newRow("uchar") << QMetaType::fromType<E1>()
|
||||
<< QMetaType::fromType<getUnderlyingTypeNormalized<E1>>();
|
||||
QTest::newRow("long") << QMetaType::fromType<E2>()
|
||||
<< QMetaType::fromType<getUnderlyingTypeNormalized<E2>>();
|
||||
QTest::newRow("class_ushort") << QMetaType::fromType<E3>()
|
||||
<< QMetaType::fromType<getUnderlyingTypeNormalized<E3>>();
|
||||
QTest::newRow("flags_int") << QMetaType::fromType<myflags::Flags1>()
|
||||
<< QMetaType::fromType<int>();
|
||||
QTest::newRow("flags_short") << QMetaType::fromType<myflags::Flags2>()
|
||||
<< QMetaType::fromType<int>(); // sic, not short!
|
||||
}
|
||||
|
||||
void tst_QMetaType::underlyingType()
|
||||
{
|
||||
QFETCH(QMetaType, source);
|
||||
QFETCH(QMetaType, underlying);
|
||||
QCOMPARE(source.underlyingType(), underlying);
|
||||
}
|
||||
|
||||
void tst_QMetaType::isRegisteredStaticLess_data()
|
||||
{
|
||||
isRegistered_data();
|
||||
|
@ -91,6 +91,8 @@ private slots:
|
||||
void isRegisteredStaticLess();
|
||||
void isNotRegistered();
|
||||
void isEnum();
|
||||
void underlyingType_data();
|
||||
void underlyingType();
|
||||
void automaticTemplateRegistration_1();
|
||||
void automaticTemplateRegistration_2(); // defined in tst_qmetatype3.cpp
|
||||
void saveAndLoadBuiltin_data();
|
||||
|
Loading…
x
Reference in New Issue
Block a user