Auto-generated properties by macros failed due to using an included definition file.
-
Hello guys, I'm composing a Qt class with many qt properties. So, I want to use macros to reduce repeating work. My code looks like this:
// myservice.h // the myservice.cpp is trivial, nothing more than an auto-generated constructor. #ifndef MYSERVICE_H #define MYSERVICE_H #include <QObject> class MyService : public QObject { Q_OBJECT public: explicit MyService(QObject *parent = nullptr); #define MY_PROPERTY(type, name) \ Q_PROPERTY(type name MEMBER m_##name NOTIFY name##Changed) #include "property_list" #undef MY_PROPERTY signals: #define MY_PROPERTY(type, name) \ void name##Changed(type); #include "property_list" #undef MY_PROPERTY private: #define MY_PROPERTY(type, name) \ type m_##name; #include "property_list" #undef MY_PROPERTY }; #endif // MYSERVICE_H
And I'm using a property_list file to define properties, it looks like this:
MY_PROPERTY(QString, value1) MY_PROPERTY(QString, value2)
But during building, I got these errors:
moc_myservice.cpp: In static member function ‘static void MyService::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)’: moc_myservice.cpp:92:41: error: no matching function for call to ‘MyService::value1Changed()’ 92 | Q_EMIT _t->value1Changed(); | ~~~~~~~~~~~~~~~~~^~ In file included from moc_myservice.cpp:10: ../qt01/property_list:1:22: note: candidate: ‘void MyService::value1Changed(QString)’ 1 | MY_PROPERTY(QString, value1) | ^~~~~~ ../qt01/myservice.h:19:10: note: in definition of macro ‘MY_PROPERTY’ 19 | void name##Changed(type); | ^~~~ ../qt01/property_list:1:22: note: candidate expects 1 argument, 0 provided 1 | MY_PROPERTY(QString, value1) | ^~~~~~ ../qt01/myservice.h:19:10: note: in definition of macro ‘MY_PROPERTY’ 19 | void name##Changed(type); | ^~~~ moc_myservice.cpp:98:41: error: no matching function for call to ‘MyService::value2Changed()’ 98 | Q_EMIT _t->value2Changed(); | ~~~~~~~~~~~~~~~~~^~ ../qt01/property_list:2:22: note: candidate: ‘void MyService::value2Changed(QString)’ 2 | MY_PROPERTY(QString, value2) | ^~~~~~ ../qt01/myservice.h:19:10: note: in definition of macro ‘MY_PROPERTY’ 19 | void name##Changed(type); | ^~~~ ../qt01/property_list:2:22: note: candidate expects 1 argument, 0 provided 2 | MY_PROPERTY(QString, value2) | ^~~~~~ ../qt01/myservice.h:19:10: note: in definition of macro ‘MY_PROPERTY’ 19 | void name##Changed(type); | ^~~~ moc_myservice.cpp: In function ‘void checkNotifySignalValidity_MyService(MyService*)’: moc_myservice.cpp:164:21: error: no matching function for call to ‘MyService::value1Changed()’ 164 | t->value1Changed(); | ~~~~~~~~~~~~~~~~^~ ../qt01/property_list:1:22: note: candidate: ‘void MyService::value1Changed(QString)’ 1 | MY_PROPERTY(QString, value1) | ^~~~~~ ../qt01/myservice.h:19:10: note: in definition of macro ‘MY_PROPERTY’ 19 | void name##Changed(type); | ^~~~ ../qt01/property_list:1:22: note: candidate expects 1 argument, 0 provided 1 | MY_PROPERTY(QString, value1) | ^~~~~~ ../qt01/myservice.h:19:10: note: in definition of macro ‘MY_PROPERTY’ 19 | void name##Changed(type); | ^~~~ moc_myservice.cpp:165:21: error: no matching function for call to ‘MyService::value2Changed()’ 165 | t->value2Changed(); | ~~~~~~~~~~~~~~~~^~ ../qt01/property_list:2:22: note: candidate: ‘void MyService::value2Changed(QString)’ 2 | MY_PROPERTY(QString, value2) | ^~~~~~ ../qt01/myservice.h:19:10: note: in definition of macro ‘MY_PROPERTY’ 19 | void name##Changed(type); | ^~~~ ../qt01/property_list:2:22: note: candidate expects 1 argument, 0 provided 2 | MY_PROPERTY(QString, value2) | ^~~~~~ ../qt01/myservice.h:19:10: note: in definition of macro ‘MY_PROPERTY’ 19 | void name##Changed(type); | ^~~~
It looks like Qt doesn't generate correct signal definitions. And I found that if I don't use a #include directive on signal macros, but paste property_list file's content like this:
signals: #define MY_PROPERTY(type, name) \ void name##Changed(type); MY_PROPERTY(QString, value1) MY_PROPERTY(QString, value2) #undef MY_PROPERTY
All errors will then disappear.
I've tried both Windows & Linux. Windows's compiler version is gcc 7.3 and linux's version is gcc 12.2. They both do the same thing.
So here is the problem:- Why a #include directive differs to pasting the content of the included file here?
- Is there a way to resolve this problem except pasting the file's content?
Thanks a lot for any help.
-
It's not a compiler problem but the moc parser. This can only be fixed when someone enhance moc but I guess the usecase is to rare that someone is willing to do it.
-
@Christian-Ehrlicher Thanks a lot. I got this problem on qt5. I'll try qt6 and if it has the same problem I'll try to file a bug to make it known to qt dev team at least.
-
@farta it will not work with Qt6 either. You can create a bug report but this limitation is already known. There were attempts to use llvm for the parser but it was to slow.
-
@Christian-Ehrlicher lol if it is a known issue maybe it is not a good idea to report it again. Do you have the bug link at hand right now?
-
@farta you can create a bug report - should not hurt.
Search for 'moc' and 'llvm' - maybe there is a task for it. -
@Christian-Ehrlicher OK my bug posted.
https://bugreports.qt.io/browse/QTBUG-116012
Hope for the dev team it means sth.
-
You should attach a minimal, compilable example to the bug report.
-
@Christian-Ehrlicher Thank you for your advice. The sample code has been added to the bug report.