Qt Q_PROPERTY与模板访问器

时间:2012-10-02 11:09:08

标签: qt templates properties moc

我的目标是更多的代码重用,同时保持冗长。

请考虑以下示例代码:

// 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;
}

这个编译并按预期运行。

如果你想知道为什么我会这样 - 想象一组属性,DESIGNABLE等,但是属于同一个“类” - 在这种情况下,我希望有单独的属性,使用enum-templatetyped存取。

取消注释属性定义会导致以下moc错误:

/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"

关于如何正确混合模板和moc的任何想法?


回答cmannet85的评论,并添加更多洞察力 - 是的,moc调用从moc_test.cpp生成moc.h

为了进一步测试和演示,我添加了另一个属性

Q_PROPERTY(int baz1 READ baz1)

之前和之后的moc_test.cpp之间的区别是:

--- 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

绝对没有什么可以阻止moc复制整个条&lt; 1&gt; QMetaObject::ReadProperty转换语句中的语句 - 但它以某种方式在&lt;&gt;上的barfs模板标签。

3 个答案:

答案 0 :(得分:3)

moc不喜欢Q_PROPERTY声明中的模板括号。您可以执行以下操作:

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;
};

moc生成的代码应该能够访问类的私有方法,并且这种间接不应该导致任何运行时成本,因为编译器可以内联对bar_N的调用。

您可能希望在宏中隐藏bar_N的声明。

答案 1 :(得分:1)

行。我想我几乎把这个想出来了。它只是邪恶的。命名空间污染 - 在包含我的头文件之前moc_test.cpp似乎没有DEFINE。

仅仅定义

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

完成了这项工作 - 但我更喜欢{M}仅在MOC运行期间(简单)和___BAR1编译期间定义{。}}。

包围

moc_test.cpp
除了moc之外,

隐藏了除了它之外的任何东西,但它不相关 - 当它编译moc_test.cpp时它也被gcc隐藏了

答案 2 :(得分:0)

只需将 () 放在 reader 函数周围:

Q_PROPERTY(int bar1 READ (bar<1>))