Как можно определить макрос C IFARGS(YES, NO, ...)
, так что IFARGS
без дополнительных аргументов вызывает NO
, а IFARGS
с одним или несколькими аргументами дает YES
?
У меня есть ответ с использованием GCC (см. Ниже), но я предпочел бы один для C99, если это возможно (или доказательство его невозможности).
В C99 можно определить, является ли аргумент макроса пустым, но делает это устойчивым против всех коэффициентов, которые могут появляться в этом аргументе (аргументы, которые сами расширяются, содержат ()
и т. Д.) Сложно. Мой пакет макросов P99 реализует такую вещь, поэтому вам не придется слишком беспокоиться. При этом ваш макрос может быть реализован как
#define IFARGS(YES, NO, ...) P99_IF_EMPTY(__VA_ARGS__)(YES(__VA__ARGS__))(NO())
Как видно из названия, P99 работает только с функциями C99.
#define GET(_0, _1) _0 // Return the first of two arguments #define GET_(_0, _1) _1 // Return the second of two arguments #define JOIN(_0, _1) _0 ## _1 // Concatenate two arguments #define EJOIN(_0, _1) JOIN(_0, _1) // Expand macros and concatenate #define FIRST(_, ...) _ // Truncate everything after first comma #define EFIRST(_) FIRST(_) // Expand argument and pass to FIRST #define REST(_0, ...) __VA_ARGS__ // Remove everything before first comma #define GET_GET(...) \ EJOIN(GET, EFIRST(REST(,,##__VA_ARGS__ _))) // Branch between GET and GET_ #define IFARGS(YES, NO, ...) GET_GET(__VA_ARGS__)(YES, NO)
Заметим, что если бы это было возможно на C99, тогда можно было бы имитировать ##__VA_ARGS__
, например:
#define PREPEND_COMMA(...) , __VA_ARGS__ #define NO_COMMA() #define PREPEND_COMMA_IF_NONEMPTY(...) IFARGS(PREPEND_COMMA, NO_COMMA, __VA_ARGS__)(__VA_ARGS__)
Тогда любой экземпляр , ##__VA_ARGS__
можно заменить PREPEND_COMMA_IF_NONEMPTY(__VA_ARGS__)
.