Question

I'm aiming for a little bit more code reuse, while maintaining verbosity.

Consider the following sample code:

// qdot@defixio /tmp/test4 $ cat test.h
#include <QObject>

class Foo : public QObject {
  Q_OBJECT
  // Q_PROPERTY(int bar1 READ bar<1>)
  // Q_PROPERTY(int bar2 READ bar<2>)

  public:
  template <int i> int bar() const;
};

// qdot@defixio /tmp/test4 $ cat test.cpp 
#include "test.h"
#include <QDebug>


template <int i> 
int Foo::bar() const { qDebug() << "Template parameter" <<  i; } 

int main() {
  Foo foo;
  foo.bar<1>();
  foo.bar<2>();
  return 0;
}

This one compiles and runs as expected.

In case you're wondering why I would like that - imagine a set of properties, DESIGNABLE, etc, but falling under the same "class" - in that case, I would like to have separate properties, using enum-templatetyped accessors.

Uncommenting the property definitions, results in the following moc error:

/usr/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. test.h -o moc_test.cpp
test.h:5: Parse error at "bar"

Any idea on how to properly mix templating and moc?


To answer cmannet85's comment, and add more insight - yes, that moc invocation generates moc_test.cpp from moc.h.

To test and demonstrate it further, I added another property

Q_PROPERTY(int baz1 READ baz1)

and the diff between moc_test.cpp before and after is this:

--- moc_test.cpp        2012-10-02 13:23:39.442333849 +0200
+++ moc_test_baz1.cpp   2012-10-02 13:23:29.822328462 +0200
@@ -1,7 +1,7 @@
 /****************************************************************************
 ** Meta object code from reading C++ file 'test.h'
 **
-** Created: Tue Oct 2 13:23:39 2012
+** Created: Tue Oct 2 13:22:27 2012
 **      by: The Qt Meta Object Compiler version 63 (Qt 4.8.3)
 **
 ** WARNING! All changes made in this file will be lost!
@@ -24,17 +24,20 @@
        0,       // classname
        0,    0, // classinfo
        0,    0, // methods
-       0,    0, // properties
+       1,   14, // properties
        0,    0, // enums/sets
        0,    0, // constructors
        0,       // flags
        0,       // signalCount

+ // properties: name, type, flags
+       8,    4, 0x02095001,
+
        0        // eod
 };

 static const char qt_meta_stringdata_Foo[] = {
-    "Foo\0"
+    "Foo\0int\0baz1\0"
 };

 void Foo::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
@@ -76,6 +79,30 @@
     _id = QObject::qt_metacall(_c, _id, _a);
     if (_id < 0)
         return _id;
+    
+#ifndef QT_NO_PROPERTIES
+     if (_c == QMetaObject::ReadProperty) {
+        void *_v = _a[0];
+        switch (_id) {
+        case 0: *reinterpret_cast< int*>(_v) = baz1(); break;
+        }
+        _id -= 1;
+    } else if (_c == QMetaObject::WriteProperty) {
+        _id -= 1;
+    } else if (_c == QMetaObject::ResetProperty) {
+        _id -= 1;
+    } else if (_c == QMetaObject::QueryPropertyDesignable) {
+        _id -= 1;
+    } else if (_c == QMetaObject::QueryPropertyScriptable) {
+        _id -= 1;
+    } else if (_c == QMetaObject::QueryPropertyStored) {
+        _id -= 1;
+    } else if (_c == QMetaObject::QueryPropertyEditable) {
+        _id -= 1;
+    } else if (_c == QMetaObject::QueryPropertyUser) {
+        _id -= 1;
+    }
+#endif // QT_NO_PROPERTIES
     return _id;
 }
 QT_END_MOC_NAMESPACE

There is absolutely nothing to prevent moc from just copying over the entire bar<1> statements into the QMetaObject::ReadProperty switch statements - but it somehow barfs on the <> template tags.

Was it helpful?

Solution

moc does not like template braces inside Q_PROPERTY declarations. You can do the following:

class Foo : public QObject {
  Q_OBJECT
  Q_PROPERTY(int bar1 READ bar_1)
  Q_PROPERTY(int bar2 READ bar_2)

  private:
  inline int bar_1() const { return bar<1>(); }
  inline int bar_2() const { return bar<2>(); }

  public:
  template <int i> int bar() const;
};

The code generated by moc should be able to access private methods of your class, and this indirection should not induce any runtime cost since the compiler can inline the calls to bar_N.

You probably want to hide the declaration of bar_N in a macro.

OTHER TIPS

OK. I think I almost figured this one out. It's just evil.due to namespace pollution - and there seem to be no DEFINE in moc_test.cpp prior to including my header file.

merely defining

#define ___BAR1 bar<1> 
Q_PROPERTY(int bar1 READ ___BAR1) 

did the job - I would however prefer if ___BAR1 was only defined during MOC run (easy) and during moc_test.cpp compilation.

Bracketing

#ifdef Q_MOC_RUN
#define ___BAR1 bar<1> 
#endif Q_MOC_RUN

hides the define from anything but moc, but it's irrlelevant - it's also hidden from gcc when it compiles moc_test.cpp

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top