Перегрузка макроса по количеству аргументов
У меня есть два макроса FOO2
и FOO3
:
#define FOO2(x,y) ... #define FOO3(x,y,z) ...
Я хочу определить новый макрос FOO
следующим образом:
#define FOO(x,y) FOO2(x,y) #define FOO(x,y,z) FOO3(x,y,z)
Но это не работает, потому что macros не перегружают количество аргументов.
- Как определить платформу / компилятор из макросов препроцессора?
- CGEventPost - возможная ошибка при имитации событий клавиатуры?
- C Макросы для создания строк
- Являются ли typedef и #define одинаковыми в c?
- Запятая в макросе C / C ++
Без изменения FOO2
и FOO3
существует ли способ определить макрос FOO
(используя __VA_ARGS__
или иначе), чтобы получить тот же эффект от отправки FOO(x,y)
в FOO2
и FOO(x,y,z)
в FOO3
?
- C многострочный макрос: do / while (0) vs scope block
- Найти (и убить) процесс блокировки порта 3000 на Mac
- Для чего нужны macros C?
- Core Data vs SQLite 3
- Врач-врач говорит: «Предупреждение: / usr / local / include не доступно для записи».
- Как избежать символа # в макросе #define?
- Как использовать Objective-C #define из Swift
- Вариадические рекурсивные macros препроцессора - возможно ли это?
Просто:
#define GET_MACRO(_1,_2,_3,NAME,...) NAME #define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__)
Итак, если у вас есть эти macros:
FOO(World, !) # expands to FOO2(World, !) FOO(foo,bar,baz) # expands to FOO3(foo,bar,baz)
Если вы хотите четвертый:
#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME #define FOO(...) GET_MACRO(__VA_ARGS__, FOO4, FOO3, FOO2)(__VA_ARGS__) FOO(a,b,c,d) # expeands to FOO4(a,b,c,d)
Естественно, если вы определите FOO2
, FOO3
и FOO4
, то результат будет заменен на те из определенных макросов.
Чтобы добавить ответ netcoder , вы можете сделать это с помощью макроса с 0 аргументами с помощью расширения GCC ##__VA_ARGS__
:
#define GET_MACRO(_0, _1, _2, NAME, ...) NAME #define FOO(...) GET_MACRO(_0, ##__VA_ARGS__, FOO2, FOO1, FOO0)(__VA_ARGS__)
Вот более общее решение:
// get number of arguments with __NARG__ #define __NARG__(...) __NARG_I_(__VA_ARGS__,__RSEQ_N()) #define __NARG_I_(...) __ARG_N(__VA_ARGS__) #define __ARG_N( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ _61,_62,_63,N,...) N #define __RSEQ_N() \ 63,62,61,60, \ 59,58,57,56,55,54,53,52,51,50, \ 49,48,47,46,45,44,43,42,41,40, \ 39,38,37,36,35,34,33,32,31,30, \ 29,28,27,26,25,24,23,22,21,20, \ 19,18,17,16,15,14,13,12,11,10, \ 9,8,7,6,5,4,3,2,1,0 // general definition for any function name #define _VFUNC_(name, n) name##n #define _VFUNC(name, n) _VFUNC_(name, n) #define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__) // definition for FOO #define FOO(...) VFUNC(FOO, __VA_ARGS__)
Определите свои функции:
#define FOO2(x, y) ((x) + (y)) #define FOO3(x, y, z) ((x) + (y) + (z)) // it also works with C functions: int FOO4(int a, int b, int c, int d) { return a + b + c + d; }
Теперь вы можете использовать FOO
с аргументами 2, 3 и 4:
FOO(42, 42) // will use makro function FOO2 FOO(42, 42, 42) // will use makro function FOO3 FOO(42, 42, 42, 42) // will call FOO4 function
Ограничения
- Только до 63 аргументов (но расширяемых)
- Функция без аргументов только в GCC возможна
идеи
Используйте его для аргументов по умолчанию:
#define func(...) VFUNC(func, __VA_ARGS__) #define func2(a, b) func4(a, b, NULL, NULL) #define func3(a, b, c) func4(a, b, c, NULL) // real function: int func4(int a, int b, void* c, void* d) { /* ... */ }
Используйте его для функций с возможным бесконечным числом аргументов:
#define SUM(...) VFUNC(SUM, __VA_ARGS__) #define SUM2(a, b) ((a) + (b)) #define SUM3(a, b, c) ((a) + (b) + (c)) #define SUM4(a, b, c) ((a) + (b) + (c) + (d)) // ...
PS: __NARG__
копируется с: https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1
Я просто изучал это сам, и я наткнулся на это здесь . Автор добавил поддержку аргументов по умолчанию для функций C через macros.
Я попытаюсь кратко обобщить статью. В принципе, вам нужно определить макрос, который может подсчитывать аргументы. Этот макрос вернет 2, 1, 0 или любой диапазон аргументов, которые он может поддерживать. Например:
#define _ARG2(_0, _1, _2, ...) _2 #define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)
При этом вам нужно создать еще один макрос, который принимает переменное количество аргументов, подсчитывает аргументы и вызывает соответствующий макрос. Я взял ваш пример макроса и объединил его с примером статьи. У меня есть функция вызова FOO1 a () и функция вызова FOO2 a с аргументом b (очевидно, я предполагаю C ++ здесь, но вы можете изменить макрос на что угодно).
#define FOO1(a) a(); #define FOO2(a,b) a(b); #define _ARG2(_0, _1, _2, ...) _2 #define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0) #define _ONE_OR_TWO_ARGS_1(a) FOO1(a) #define _ONE_OR_TWO_ARGS_2(a, b) FOO2(a,b) #define __ONE_OR_TWO_ARGS(N, ...) _ONE_OR_TWO_ARGS_ ## N (__VA_ARGS__) #define _ONE_OR_TWO_ARGS(N, ...) __ONE_OR_TWO_ARGS(N, __VA_ARGS__) #define FOO(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__)
Поэтому, если у вас есть
FOO(a) FOO(a,b)
Препроцессор расширяет это значение до
a(); a(b);
Я бы определенно прочитал статью, которую я связал. Это очень информативно, и он упоминает, что NARG2 не будет работать над пустым аргументом. Он следует за этим здесь .
Вот более компактная версия ответа выше . Пример.
#include using namespace std; #define OVERLOADED_MACRO(M, ...) _OVR(M, _COUNT_ARGS(__VA_ARGS__)) (__VA_ARGS__) #define _OVR(macroName, number_of_args) _OVR_EXPAND(macroName, number_of_args) #define _OVR_EXPAND(macroName, number_of_args) macroName##number_of_args #define _COUNT_ARGS(...) _ARG_PATTERN_MATCH(__VA_ARGS__, 9,8,7,6,5,4,3,2,1) #define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9, N, ...) N //Example: #define ff(...) OVERLOADED_MACRO(ff, __VA_ARGS__) #define ii(...) OVERLOADED_MACRO(ii, __VA_ARGS__) #define ff3(c, a, b) for (int c = int(a); c < int(b); ++c) #define ff2(c, b) ff3(c, 0, b) #define ii2(a, b) ff3(i, a, b) #define ii1(n) ii2(0, n) int main() { ff (counter, 3, 5) cout << "counter = " << counter << endl; ff (abc, 4) cout << "abc = " << abc << endl; ii (3) cout << "i = " << i << endl; ii (100, 103) cout << "i = " << i << endl; return 0; }
Бег:
[email protected] 13:06:16 /c/T $ g++ test_overloaded_macros.cpp [email protected] 13:16:26 /c/T $ ./a.exe counter = 3 counter = 4 abc = 0 abc = 1 abc = 2 abc = 3 i = 0 i = 1 i = 2 i = 100 i = 101 i = 102
Обратите внимание, что наличие как _OVR
и _OVR_EXPAND
может выглядеть избыточным, но для препроцессора необходимо расширить часть _COUNT_ARGS(__VA_ARGS__)
, которая в противном случае обрабатывается как строка.
Возможно, вы можете использовать этот макрос для подсчета количества аргументов .
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1) #define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
Вот от ответа Евгения Сергеева. Это также поддерживает перегрузку нулевого аргумента !
Я тестировал это с помощью GCC и MinGW. Он должен работать со старыми и новыми версиями C ++. Заметьте, что я бы не гарантировал это для MSVC … Но с некоторой настройкой, я уверен, что это может быть сделано для работы с этим тоже.
Я также отформатировал это для вставки в файл заголовка (который я назвал macroutil.h). Если вы это сделаете, вы можете просто включить этот заголовок, что бы вам ни понадобилось, и не смотреть на гадость, вовлеченную в реализацию.
#ifndef MACROUTIL_H #define MACROUTIL_H //----------------------------------------------------------------------------- // OVERLOADED_MACRO // // used to create other macros with overloaded argument lists // // Example Use: // #define myMacro(...) OVERLOADED_MACRO( myMacro, __VA_ARGS__ ) // #define myMacro0() someFunc() // #define myMacro1( arg1 ) someFunc( arg1 ) // #define myMacro2( arg1, arg2 ) someFunc( arg1, arg2 ) // // myMacro(); // myMacro(1); // myMacro(1,2); // // Note the numerical suffix on the macro names, // which indicates the number of arguments. // That is the REQUIRED naming convention for your macros. // //----------------------------------------------------------------------------- // OVERLOADED_MACRO // derived from: https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments // replaced use of _COUNT_ARGS macro with VA_NUM_ARGS defined below // to support of zero argument overloads #define OVERLOADED_MACRO(M, ...) _OVR(M, VA_NUM_ARGS(__VA_ARGS__)) (__VA_ARGS__) #define _OVR(macroName, number_of_args) _OVR_EXPAND(macroName, number_of_args) #define _OVR_EXPAND(macroName, number_of_args) macroName##number_of_args //#define _COUNT_ARGS(...) _ARG_PATTERN_MATCH(__VA_ARGS__, 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) #define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15, N, ...) N // VA_NUM_ARGS // copied from comments section of: // http://efesx.com/2010/07/17/variadic-macro-to-count-number-of-arguments/ // which itself was derived from: // https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ #define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15 #define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) #define HAS_NO_COMMA(...) _ARG16(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1) #define _TRIGGER_PARENTHESIS_(...) , #define HAS_ZERO_OR_ONE_ARGS(...) \ _HAS_ZERO_OR_ONE_ARGS( \ /* test if there is just one argument, eventually an empty one */ \ HAS_COMMA(__VA_ARGS__), \ /* test if _TRIGGER_PARENTHESIS_ together with the argument adds a comma */ \ HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \ /* test if the argument together with a parenthesis adds a comma */ \ HAS_COMMA(__VA_ARGS__ (~)), \ /* test if placing it between _TRIGGER_PARENTHESIS_ and the parenthesis adds a comma */ \ HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (~)) \ ) #define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4 #define _HAS_ZERO_OR_ONE_ARGS(_0, _1, _2, _3) HAS_NO_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3)) #define _IS_EMPTY_CASE_0001 , #define _VA0(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__) #define _VA1(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__) #define _VA2(...) 2 #define _VA3(...) 3 #define _VA4(...) 4 #define _VA5(...) 5 #define _VA6(...) 6 #define _VA7(...) 7 #define _VA8(...) 8 #define _VA9(...) 9 #define _VA10(...) 10 #define _VA11(...) 11 #define _VA12(...) 12 #define _VA13(...) 13 #define _VA14(...) 14 #define _VA15(...) 15 #define _VA16(...) 16 #define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, PP_RSEQ_N(__VA_ARGS__) ) #define VA_NUM_ARGS_IMPL(...) VA_NUM_ARGS_N(__VA_ARGS__) #define VA_NUM_ARGS_N( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _11,_12,_13,_14,_15,_16,N,...) N #define PP_RSEQ_N(...) \ _VA16(__VA_ARGS__),_VA15(__VA_ARGS__),_VA14(__VA_ARGS__),_VA13(__VA_ARGS__), \ _VA12(__VA_ARGS__),_VA11(__VA_ARGS__),_VA10(__VA_ARGS__), _VA9(__VA_ARGS__), \ _VA8(__VA_ARGS__),_VA7(__VA_ARGS__),_VA6(__VA_ARGS__),_VA5(__VA_ARGS__), \ _VA4(__VA_ARGS__),_VA3(__VA_ARGS__),_VA2(__VA_ARGS__),_VA1(__VA_ARGS__), \ _VA0(__VA_ARGS__) //----------------------------------------------------------------------------- #endif // MACROUTIL_H
Это, похоже, отлично работает на GCC, Clang и MSVC. Некоторые из ответов здесь вычищены.
#define __BUGFX(x) x #define __NARG2(...) __BUGFX(__NARG1(__VA_ARGS__,__RSEQN())) #define __NARG1(...) __BUGFX(__ARGSN(__VA_ARGS__)) #define __ARGSN(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N #define __RSEQN() 10,9,8,7,6,5,4,3,2,1,0 #define __FUNC2(name,n) name ## n #define __FUNC1(name,n) __FUNC2(name,n) #define GET_MACRO(func,...) __FUNC1(func,__BUGFX(__NARG2(__VA_ARGS__))) (__VA_ARGS__)