Variadic макросы с нулевыми аргументами - PullRequest
18 голосов
/ 05 мая 2011

Я работаю над макросом вызова,

#define CALL(f,...) FN(f)->call((ref(new LinkedList()), __VA_ARGS__))

, который при вызове

CALL(print,2,3,4,5);

добавляет 2 3 4 5 в связанный список (перегружен для этого)и вызывает print, которая ожидает связанный список, который работает, как и ожидалось, как бы то ни было, некоторые вызовы, которые не требуют аргументов,

CALL(HeapSize);

Он по-прежнему принимает связанный список, но пустой, выше не работает, яя пытаюсь найти макрос, который будет работать с любым из этих стилей?

РЕДАКТИРОВАТЬ: копать документы gcc Я обнаружил, что добавление ## перед VA_ARGS удаляет, когда нет аргументов, нопри этом я не могу вкладывать макросы,

CALL(print,CALL(HeadSize));

это вызывает ошибку CALL, не определенную как никогда, если я разделяю вызовы, которые она работает

Ответы [ 6 ]

20 голосов
/ 05 мая 2011

Что касается обновленного вопроса, с помощью вспомогательного макроса VA_ARGS, как показано ниже, аргументы будут расширены, как и ожидалось.

#define VA_ARGS(...) , ##__VA_ARGS__
#define CALL(f,...) FN(f)->call((ref(new LinkedList()) VA_ARGS(__VA_ARGS__)))
11 голосов
/ 05 мая 2011

Если вы используете gcc / g ++, есть способ:

#define CALL(f,...) FN(f)->call((ref(new LinkedList()), ## __VA_ARGS__))

Из инструкции :

[...] если аргументы переменной опущены или пусты, оператор `## 'заставляет препроцессор удалить запятую перед ним.

Так что у gcc есть расширение / хак специально для проблемы, с которой вы столкнулись.

4 голосов
/ 05 мая 2011

Если вы используете GCC, у него есть расширение, чтобы проглотить запятую, предшествующую __VA_ARGS__. Смотри: http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html.

1 голос
/ 18 апреля 2014

Общая тема в этих ответах - нам нужен специальный взлом GCC. Одним из способов является использование token-paste ##__VAR_ARGS__, но вставленные аргументы не раскрываются макросами, что означает, что макросы не могут быть вложенными. Но если вы все равно собираетесь делать что-то специфичное для GCC, то почему бы не использовать старомодное расширение GCC:

 #define VARARG_FOO(ZeroOrMoreArgs...) \
     printf("VARARG_FOO: " ZeroOrMoreArgs)

ZeroOrMoreArgs просто заменяется всеми аргументами (если есть), запятыми и всем. Это включает в себя рекурсивное расширение макроса.

  • затем VARARG_FOO() расширяется до printf("VARARG_FOO: ")
  • и VARARG_FOO("I iz %d", 42) расширяется до printf("VARARGFOO: " "I iz %d", 42)

Наконец

 #define NEST_ME "I tawt I taw a puddy tat"
 VARARG_FOO("The evil one says %s", NEST_ME); 

расширится до

 printf("VARARG_FOO: " "The evil one says %s", "I tawt I taw a puddy tat");

Плюсы:

  • Вы можете вкладывать макро-вызовы, имея ноль или более агентов.

Минусы:

  • ##__VA_ARGS__ hack может быть безвредным в стандартных программах на C, если в них всегда есть хотя бы одна запятая. (Я не думал о том, правда это или нет).
  • Согласно @ScootMoonen, взлом ##__VA_ARGS__ является недокументированным расширением MSVC.
0 голосов
/ 05 мая 2011

Просто сделайте f частью ... и используйте отдельный макрос для извлечения первого аргумента, где вам нужно f.

0 голосов
/ 05 мая 2011

К сожалению, этого сделать нельзя. Вам нужно будет определить отдельный макрос для этого вызова.

Когда вы получите недопустимые аргументы, когда VA_ARGS заменяется ничем, вы получите плавающий ,

#define CALL0(f) FN(f)->call((ref(new LinkedList())))
...