[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