나는 두 매크로가 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)
그러나 매크로는 여러 인수에 과부하가 걸리지 않기 때문에 작동하지 않습니다.
수정하지 않고 FOO2
및 FOO3
매크로 정의하는 몇 가지 방법이있다 FOO
(사용 __VA_ARGS__
파견 같은 효과를 얻을 수있는 다른 나) FOO(x,y)
에 FOO2
, 그리고 FOO(x,y,z)
하려면 FOO3
?
답변
다음과 같이 간단합니다.
#define GET_MACRO(_1,_2,_3,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__)
따라서 이러한 매크로가 있다면 :
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의 답변 에 추가하기 위해 실제로 GCC ##__VA_ARGS__
확장을 사용하여 0 인수 매크로를 사용 하여이 작업을 수행 할 수 있습니다.
#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))
// ...
추신 : __NARG__
Laurent Deniau & Roland Illig에서 복사했습니다 : https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1
답변
나는 이것을 스스로 연구하고 있었고 여기 에서 이것을 보았습니다 . 저자는 매크로를 통해 C 함수에 대한 기본 인수 지원을 추가했습니다.
나는 기사를 간단히 요약하려고 노력할 것이다. 기본적으로 인수를 계산할 수있는 매크로를 정의해야합니다. 이 매크로는 2, 1, 0 또는 지원 가능한 모든 범위의 인수를 반환합니다. 예 :
#define _ARG2(_0, _1, _2, ...) _2
#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)
이를 통해 가변 개수의 인수를 취하고 인수를 세고 적절한 매크로를 호출하는 다른 매크로를 작성해야합니다. 예제 매크로를 가져 와서 기사 예제와 결합했습니다. FOO1 호출 함수 a () 및 FOO2 호출 함수 a와 인수 b가 있습니다.
#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 <iostream>
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;
}
운영:
User@Table 13:06:16 /c/T
$ g++ test_overloaded_macros.cpp
User@Table 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
답변
Evgeni Sergeev의 답변에서 나온 내용입니다. 이것도 제로 인수 과부하 를 지원 합니다 !
나는 이것을 GCC와 MinGW로 테스트했다. 이전 버전과 새로운 버전의 C ++에서 작동해야합니다. MSVC에 대해서는 보장하지 않을 것입니다 …하지만 약간의 조정으로도 작동 할 수 있다고 확신합니다.
또한 헤더 파일 (매크로 유틸리티 .h라고 함)에 붙여 넣도록이 형식을 지정했습니다. 그렇게하면 기능이 필요한 것이 무엇이든이 헤더를 포함시킬 수 있으며 구현과 관련된 nastiness를 보지 마십시오.
#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: /programming/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