На мой взгляд, использование функционального макроса в C++ похоже на использование обычной функции. Кажется, это так:
macroFunctionName(arg1, arg2, arg3);
Однако использование Q_PROPERTY обычно выглядит так:
Q_PROPERTY(Qt::WindowModality windowModality READ windowModality WRITE setWindowModality)
Как мы видим, они разные. В использовании Q_PROPERTY нет запятой. Я никогда не видел макроса, похожего на функцию, который использовался бы как Q_PROPERTY. Я даже не уверен, является ли Q_PROPERTY макросом, подобным функции в C++. Так это неправильно в C++? Или это просто специальный синтаксис для MOC в Qt?
Я пытался найти его в стандартном документе С++, но ничего о нем не нашел.





Я посмотрел в файле Qt ./src/corelib/kernel/qobjectdefs.h определение, и оно выглядит так:
#define Q_PROPERTY(...) QT_ANNOTATE_CLASS(qt_property, __VA_ARGS__)
... что сделало бы Q_PROPERTY вариативным макросом. Конечно, все, что он делает, это расширяется до QT_ANNOTATE_CLASS, который представляет собой другой макрос, который moc утилита Qt предположительно знает, как осмысленно обрабатывать при создании своих moc_*.cpp файлов.
Что касается использования пробелов, а не запятых; вы правы, препроцессор не рассматривает пробелы как разделители аргументов. Я подозреваю, что препроцессор C++ просто передает всю строку (например, "Qt::WindowModality windowModality READ windowModality WRITE setWindowModality") в макрос QT_ANNOTATE_CLASS в качестве одного аргумента, и макроопределение QT_ANNOTATE_CLASS этого moc выполняет некоторые трюки с препроцессором стробирования., чтобы проанализировать его как строку-аргумент.
Я подозреваю, что READ, WRITE и все остальные теги, которые вы можете поместить в эту строку, сами по себе являются макросами, возможно, содержащими запятые.
Хм, я не думал о такой возможности ... может быть, это то, что они делают, хотя рекурсивный grep заголовков Qt не сразу дает что-то вроде #define READ do_something_clever,
Связанный: Каково значение Q_PROPERTY в Qt?