Важным фактом о макросах C / C ++ является то, что их невозможно вызвать без параметров, потому что параметр макроса может быть пустой последовательностью токенов.
Следовательно, DUMMY()
вызывает макрос DUMMY
с одним пустым параметром, а не с нулевыми параметрами. Это объясняет, почему работает второй пример, а также объясняет, почему первый пример вызывает синтаксическую ошибку.
Расширение GCC удаляет запятую из , ##__VA_ARGS__
, когда __VA_ARGS__
не имеет элементов. Но один пустой аргумент - это не то же самое, что отсутствие аргументов. Когда вы определяете DUMMY
как #define DUMMY(...)
, вы гарантируете, что __VA_ARGS__
имеет хотя бы один аргумент, поэтому ,
не будет удален.
*** Примечание: GCC делает исключение из этого правила, если вы не укажете какой-либо стандарт ISO с параметром --std
. В этом случае, если ...
является единственным параметром макроса и вызов имеет пустой аргумент, тогда ,##__VA_ARGS__
удаляет запятую. Это указано в руководстве по CPP в раздел Variadic Marcos:
Вышеупомянутое объяснение неоднозначно в отношении случая, когда единственный параметр макроса является параметром переменных аргументов, поскольку бессмысленно пытаться различать, является ли вообще никакой аргумент пустым или отсутствующим аргументом. CPP сохраняет запятую при соответствии определенному стандарту C. В противном случае запятая опускается как расширение стандарта.
Когда DUMMY
равно #define DUMMY(x, ...)
, __VA_ARGS
будет пустым, если DUMMY
вызывается только с одним аргументом, который включает как вызовы DUMMY()
(один пустой аргумент), так и DUMMY(0)
(один аргумент, 0
). Обратите внимание, что стандартный C и C ++ до C ++ 20 не допускают этого вызова; они требуют, чтобы был хотя бы один (возможно, пустой) аргумент, соответствующий многоточию. Однако GCC никогда не налагал этого ограничения, и GCC будет опускать запятую с ,##__VA_ARGS__
независимо от параметра --std
.
Начиная с C ++ 20, вы можете использовать встроенный макрос __VA_OPT__
как более стандартный способ работы с запятыми (и любыми другими знаками препинания, которые, возможно, потребуется удалить). __VA_OPT__
также позволяет избежать проблемы, представленной выше с пустыми аргументами, потому что он использует другой критерий: __VA_OPT__(x)
заменяется на x
, если __VA_ARGS__
содержит хотя бы один токен; в противном случае он расширяется до пустой последовательности. Следовательно, __VA_OPT__
будет работать должным образом для макросов в этом вопросе.
Я считаю, что все основные компиляторы теперь реализуют __VA_OPT__
, по крайней мере, в своих последних версиях.
person
rici
schedule
06.09.2020
Dummy("Hello",);
:( coliru. - person anton_rh   schedule 04.09.2020