Счетчик аргументов макроса Variadic не работает должным образом
Итак, в основном я пытаюсь реализовать макрос для подсчета количества аргументов в VA_ARGS.
Для простоты работает только до 3 параметров. Проблема в том, что когда макрос используется с менее чем 3 параметрами, он не работает и вызывает ошибку "ожидаемое выражение".
#define EXPAND( x ) x
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, PP_RSEQ_N()))
#define PP_ARG_N(_1, _2, _3, N,...) N
#define PP_RSEQ_N() 3,2,1,0
void main()
{
printf("\nTEST PP_NARG: %i", PP_NARG()); //Doesn't work (in this case it shouldn't work, so it's correct)
printf("\nTEST PP_NARG: %i", PP_NARG(0)); //Doesn't work
printf("\nTEST PP_NARG: %i", PP_NARG(0,0)); //Doesn't work
printf("\nTEST PP_NARG: %i", PP_NARG(0,0,0)); //Works
}
Сохраняя только строку, которая работает, она правильно компилируется и печатает "TEST PP_NARG: 3".
Я полагаю, что проблема может заключаться в том, что PP_RSEQ_N() расширяется только до "3", а не "3,2,1,0" по какой-то причине, поскольку даже если PP_RSEQ_N() определен так
#define PP_RSEQ_N() 10,9,8,7,6,5,4,3,2,1,0
он все еще не работает с менее чем 3 параметрами.
Я использую компилятор MSVC, и это может быть причиной проблемы, так как он не очень хорошо работает с макросами, как видно здесь: MSVC неправильно расширяет __VA_ARGS__
2 ответа
В вашей реализации PP_RSEQ_N()
это аргумент PP_ARG_N
, В качестве аргумента он раскрывается только на этапе подстановки аргумента предварительной обработки, но это происходит только перед заменой аргумента в его списке замещения (если в списке замещения он не является строковым и не участвует в вставить).
поскольку PP_ARG_N
только имеет четвертый аргумент N
в списке замены, PP_RSEQ_N()
будет расширяться только в том случае, если вы передадите три аргумента. (Во время фазы повторного сканирования и замены выполняется второе сканирование, которое применяется после замены аргумента... но здесь это не имеет никакого эффекта, так как PP_RSEQ_N()
упоминается в звонке).
Избавьтесь от этого макроса и просто поместите его в PP_NARG
как это:
#define EXPAND( x ) x
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 3,2,1,0))
#define PP_ARG_N(_1, _2, _3, N,...) N
... и вещи "работают" нормально
PP_NARG()
расширяется до 1
PP_NARG(x)
расширяется до 1
PP_NARG(x,y)
расширяется до 2
Обратите внимание, однако, что PP_NARG()
не дает вам 0. Возможно, это действительно правильно; препроцессору, это не передача нулевых аргументов. Он передает один аргумент, который просто пуст. Это то же самое, что #define X(A) OPEN A CLOSE
/X()
получая OPEN CLOSE
, Если по какой-то причине вы хотите, чтобы это увеличилось до 0, возможно, возникнет некоторая путаница, чтобы это произошло, но для этого ответа я сосредоточусь только на том, чтобы помочь вам преодолеть один этот горб.
А
PP_ARG_N()
реализацию, которая также может различать вызовы с параметром и без него, можно найти здесь (спасибо Скотту Моррисону). Ответ на вашу маленькую программу:
TEST PP_NARG: 0
TEST PP_NARG: 1
TEST PP_NARG: 2
TEST PP_NARG: 3