Задача (краткая)
(следует полный минимальный код) Почему-то, когда я передаю простой список аргументов в мой макрос, все в порядке.
#pragma message STRINGIZE( ( DUMMY_WRAPPER (initial_argument, arg2, arg3)))
Во время компиляции выше, я вижу ожидаемый вывод от компилятора / препроцессора:
#pragma message: ( initial_argument { {initial_argument, arg2} , {initial_argument, arg3} }; 2)
Однако, когда я пытаюсь определить макрос с аргументами и передать , который в DUMMY_WRAPPER
, я получаю «лишний» пустой аргумент. Пример:
#define ARGS initial_argument, arg2, arg3
#pragma message STRINGIZE( ( DUMMY_WRAPPER (ARGS) ))
Вывод компилятора (сравните с правильным выводом):
#pragma message: ( initial_argument { {initial_argument, arg2} , {initial_argument, arg3} , {initial_argument, } }; 3 )
Как избавиться от этого дополнительного аргумента?
Полный код (с пояснениями )
Примечание: я признаю, что это, вероятно, очень плохое злоупотребление макросами, и есть гораздо лучшие способы метапрограммирования на C ++, но я просто пытаюсь заставить это работать быстро.
Я использовал GCC / G ++ для компиляции.
Вот рабочий код + выходные данные компилятора, которые вы можете легко протестировать / поэкспериментировать с онлайн: https://godbolt.org/z/wGFbrK
#define COMMA() ,
// routines for stringizing macros, similar to BOOST_PP_STRINGIZE
#define STR1(x) #x
#define STRINGIZE(x) STR1(x)
// routine & subroutines for argument counting
#define NARG(...) \
NARG_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define ARG_N(_1,_2,_3,_4,_5, N, ... ) N
#define NARG_(...) ARG_N(__VA_ARGS__)
// routines for "looped" macro expansion, for processing lists of macro arguments
#define LOOP_1(M, C, D, x) M(C, x)
#define LOOP_2(M, C, D, x, ...) M(C, x) D() \
LOOP_1(M, C, D, __VA_ARGS__)
#define LOOP_3(M, C, D, x, ...) M(C, x) D() \
LOOP_2(M, C, D, __VA_ARGS__)
#define LOOP_4(M, C, D, x, ...) M(C, x) D() \
LOOP_3(M, C, D, __VA_ARGS__)
#define LOOP_5(M, C, D, x, ...) M(C, x) D() \
LOOP_4(M, C, D, __VA_ARGS__)
// routine for concatenating things, used here to expand loop routine names, i.e. LOOP_ + 3 => LOOP_3
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a##__VA_ARGS__
// **** TOP-LEVEL ****
// (code using above routines to demonstrate the problem)
// lists the first argument, i.e. C in the loop, and some other argument
#define LIST_FIELD(arg1, a, ... ) {arg1, a}
#define DUMMY_WRAPPER(arg1, ...) DUMMY( arg1, __VA_ARGS__)
#define DUMMY( arg1, ...) \
DUMMY_2(arg1, NARG(__VA_ARGS__), __VA_ARGS__)
#define DUMMY_2( arg1, field_count, ...) \
DUMMY_3(arg1, CAT(LOOP_, field_count), __VA_ARGS__) \
field_count
#define DUMMY_3( arg1, loop, ...) \
arg1 { \
loop(LIST_FIELD, arg1, COMMA, __VA_ARGS__) \
};
#pragma message STRINGIZE( ( DUMMY_WRAPPER (initial_argument, arg2, arg3)))
#define ARGS initial_argument, arg2, arg3
#pragma message STRINGIZE( ( DUMMY_WRAPPER (ARGS) ))
(Некоторые) Исследования, которые могут быть связаны (не уверен)
https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
Не уверен, что это может объяснить что-то здесь, хотя, на мой взгляд, интуитивно нет ...