[Development] Why does QFlag exist? (Not QFlags)
Eirik Aavitsland
eirik.aavitsland at qt.io
Tue Sep 10 08:00:28 CEST 2024
No idea if this is helpful, but it seems that what was later renamed
QFlag was introduced as QFlagInternal in this commit:
commit dc289baeeb131bddbe6cff5c5620f76f5fac90de
Author: Paul Olav Tvete <paul at trolltech.com>
Date: Thu Aug 7 17:44:28 2003 +0100
Also work with more pedantic compilers.
[git-p4: depot-paths = "//depot/qt/main/": change = 109613]
diff --git a/src/moc/moc.y b/src/moc/moc.y
index 977e875f3b4..818c9d7adb8 100644
--- a/src/moc/moc.y
+++ b/src/moc/moc.y
@@ -2427,10 +2427,14 @@ void generateMetacall()
fprintf(out, " case %d: _o[0] =
(void*)&%s(); break;\n",
propindex,
(const char *)p->read);
- else
+ else if (isVariantType(p->type))
fprintf(out, " case %d: *(%s*)_v = %s();
break;\n",
propindex,
- !isVariantType(p->type) ? "int" : (const
char *)p->type,
+ (const char *)p->type,
+ (const char *)p->read);
+ else
+ fprintf(out, " case %d: *(int*)_v =
(QFlagInternal)%s(); break;\n",
+ propindex,
(const char *)p->read);
}
fprintf(out,
@@ -2448,7 +2452,13 @@ void generateMetacall()
int propindex = -1;
for (p = g->props.first(); p; p = g->props.next()) {
++propindex;
- if (!p->write.isEmpty()) {
+ if (p->write.isEmpty())
+ continue;
+ if (isSetType(p->type)) {
+ fprintf(out, " case %d:
%s(QFlagInternal(*(int*)_v)); break;\n",
+ propindex,
+ (const char *)p->write );
+ } else {
fprintf(out, " case %d: %s(*(%s*)_v); break;\n",
propindex,
(const char *)p->write,
diff --git a/src/tools/qglobal.h b/src/tools/qglobal.h
index 5e124d6c286..08ab4ef761e 100644
--- a/src/tools/qglobal.h
+++ b/src/tools/qglobal.h
@@ -1186,6 +1186,15 @@ inline T qt_cast(const QObject *object)
template <> inline IFace *qt_cast<IFace *>(const QObject *object) \
{ return (IFace *)(object ? object->qt_metacast(#IFace) : 0); }
+class QFlagInternal
+{
+public:
+ QFlagInternal(int i) : i(i) {}
+ operator int() const { return i; }
+private:
+ int i;
+};
+
template<typename Enum>
class QFlags
{
@@ -1194,14 +1203,24 @@ public:
inline QFlags(const QFlags &f) : u(f.u) {}
inline QFlags(Enum f) : u(f) {}
inline QFlags(Zero * = 0) : u(0) {}
+ inline QFlags(QFlagInternal i) : u(i) {}
+ inline operator QFlagInternal() const { return u; }
inline QFlags &operator=(const QFlags &f) { u = f.u; return *this; }
- inline operator int() const { return u; }
+ inline operator Zero*() const { return reinterpret_cast<Zero*>(u ?
0x1:0x0); }
+ inline bool operator!() const { return !u; }
inline QFlags operator|(QFlags f) const { QFlags wf; wf.u = u|f.u;
return wf; }
inline QFlags operator|(Enum f) const { QFlags wf; wf.u = u|f;
return wf; }
- inline QFlags operator&(int mask) const { QFlags wf; wf.u = u&mask;
return wf; }
+// inline QFlags operator&(int mask) const { QFlags wf; wf.u =
u&mask; return wf; }
+ inline QFlags operator&(uint mask) const { QFlags wf; wf.u =
u&mask; return wf; }
+ inline QFlags operator&(QFlags f) const { QFlags wf; wf.u = u&f.u;
return wf; }
+ inline QFlags operator&(Enum f) const { QFlags wf; wf.u = u&f;
return wf; }
+ inline QFlags operator~() const { QFlags wf; wf.u = ~u; return wf; }
+
inline QFlags &operator&=(int mask) { u &= mask; return *this; }
+ inline QFlags &operator&=(QFlags f) { u &= f.u; return *this; }
+ inline QFlags &operator&=(Enum f) { u &= f; return *this; }
inline QFlags &operator|=(QFlags f) { u |= f.u; return *this; }
inline QFlags &operator|=(Enum f) { u |= f; return *this; }
On 9/10/24 02:18, Thiago Macieira wrote:
> Can someone look up the history of ths class in qflags.h? That or its use in
> src/tools/moc/generator.cpp (it's used in one line)
>
> moc uses this class to generate code for Q_PROPERTYs whose type was seen to be
> be the result of a Q_DECLARE_FLAGS. Then, instead of emitting the property
> getter/setter on the actual QFlags<E> type, it emits something based on an
> integer, such as in moc_qlibrary.cpp:
>
> case 1:
> *reinterpret_cast<LoadHints::Int *>(_v) = _t->loadHints().toInt(); break;
>
> case 1:
> _t->setLoadHints(QFlag(*reinterpret_cast<LoadHints::Int*>(_v))); break;
>
> I do not understand why it is using integers here in the first place and I
> don't think this is implemented correctly either. Before I even attempt to fix
> this, I need to understand why it emits code like above. Specifically:
>
> Why is it using QFlag instead of LoadHints::enum_type?
>
> The only reason I can think of is that this allows the setter function to take
> an integer instead of the QFlags type, because QFlag can be implicitly
> converted to any QFlags and to int. But I am not confident that this was the
> goal, as opposed to a side-effect.
>
>
> This code is NOT matched by QMetaProperty;:read and write. Those create a
> QVariant of the actual property type (the QFlags), so the reinterpret_casts to
> Int above are type punning.
>
> Also note this does not apply if the QFlags type was not seen to be a
> Q_DECLARE_FLAGS, such as when it is not from that class, as in
> (moc_qwindow.cpp):
>
> case 2: *reinterpret_cast< Qt::WindowFlags*>(_v) = _t->flags(); break;
> case 2: _t->setFlags(*reinterpret_cast< Qt::WindowFlags*>(_v)); break;
>
>
More information about the Development
mailing list