C ++ 매크로를 사용하는 선행 변수
C ++ 매크로로 구독 변수를 얻는 방법이 있습니까? 어떤 종류의 보강도 좋을 것입니다.
여기에 한 가지 방법이 있습니다. 인수 목록을 두 번 사용하여 먼저 도우미 매크로의 이름을 만든 다음 해당 도우미 매크로에 인수를 전달합니다. 표준 트릭을 사용하여 매크로에 대한 인수 수를 계산합니다.
enum
{
plain = 0,
bold = 1,
italic = 2
};
void PrintString(const char* message, int size, int style)
{
}
#define PRINT_STRING_1_ARGS(message) PrintString(message, 0, 0)
#define PRINT_STRING_2_ARGS(message, size) PrintString(message, size, 0)
#define PRINT_STRING_3_ARGS(message, size, style) PrintString(message, size, style)
#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define PRINT_STRING_MACRO_CHOOSER(...) \
GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )
#define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
int main(int argc, char * const argv[])
{
PRINT_STRING("Hello, World!");
PRINT_STRING("Hello, World!", 18);
PRINT_STRING("Hello, World!", 18, bold);
return 0;
}
이렇게하면 작성자가 아닌 매크로 호출자가 더 쉽게 수행 할 수 있습니다.
그의 답변에 대해 Derek Ledbetter에게 큰 존경을 표하며 오래된 질문을 되살린 것에 대해드립니다.
일을하고이보다 선행 할 수있는 능력에 다른 따기 있었는지의 이해를 얻기 __VA_ARGS__
로 ##
허용 나를 [해석] 변화를 가지고 올 ...
// The multiple macros that you would need anyway [as per: Crazy Eddie]
#define XXX_0() <code for no arguments>
#define XXX_1(A) <code for one argument>
#define XXX_2(A,B) <code for two arguments>
#define XXX_3(A,B,C) <code for three arguments>
#define XXX_4(A,B,C,D) <code for four arguments>
// The interim macro that simply strips the excess and ends up with the required macro
#define XXX_X(x,A,B,C,D,FUNC, ...) FUNC
// The macro that the programmer uses
#define XXX(...) XXX_X(,##__VA_ARGS__,\
XXX_4(__VA_ARGS__),\
XXX_3(__VA_ARGS__),\
XXX_2(__VA_ARGS__),\
XXX_1(__VA_ARGS__),\
XXX_0(__VA_ARGS__)\
)
답을 우연히 발견했지만 어떻게 작동하는지 잘 모르는 저와 같은 비전문가를 위해 다음 코드로 시작하여 실제 처리를 단계별로 진행하겠습니다.
XXX();
XXX(1);
XXX(1,2);
XXX(1,2,3);
XXX(1,2,3,4);
XXX(1,2,3,4,5); // Not actually valid, but included to show the process
된다 ...
XXX_X(, XXX_4(), XXX_3(), XXX_2(), XXX_1(), XXX_0() );
XXX_X(, 1, XXX_4(1), XXX_3(1), XXX_2(1), XXX_1(1), XXX_0(1) );
XXX_X(, 1, 2, XXX_4(1,2), XXX_3(1,2), XXX_2(1,2), XXX_1(1,2), XXX_0(1,2) );
XXX_X(, 1, 2, 3, XXX_4(1,2,3), XXX_3(1,2,3), XXX_2(1,2,3), XXX_1(1,2,3), XXX_0(1,2,3) );
XXX_X(, 1, 2, 3, 4, XXX_4(1,2,3,4), XXX_3(1,2,3,4), XXX_2(1,2,3,4), XXX_1(1,2,3,4), XXX_0(1,2,3,4) );
XXX_X(, 1, 2, 3, 4, 5, XXX_4(1,2,3,4,5), XXX_3(1,2,3,4,5), XXX_2(1,2,3,4,5), XXX_1(1,2,3,4,5), XXX_0(1,2,3,4,5) );
이것이 여섯 번째 주장입니다.
XXX_0();
XXX_1(1);
XXX_2(1,2);
XXX_3(1,2,3);
XXX_4(1,2,3,4);
5;
추신 : 구매 오류가 발생했을 경우 XXX_0에 대한 #define을 제거하십시오 [예 : 인수가없는 경우 제거하지 않는 경우].
PPS : 잘못된 상황 (예 : 5)이 프로그래머에게 더 명확한 오류를 제공하는 것이 좋을 것입니다!
PPPS : 저는가 아니기 때문에 의견 (좋음, 나쁨 또는 기타)을 듣게되어 매우 기쁩니다!
C ++ 매크로는 C에서 변경되지 않습니다. C에는 함수에 대한 오버로딩 및 기본 인수가 확실히 매크로에 대한 인수가 없습니다. 귀하의 질문에 대답하십시오. 아니요, 기능은 매크로에 존재하지 않습니다. 유일한 옵션은 이름이 다른 여러 매크로를 정의하는 것입니다.
참고로 : C ++에서는 일반적으로 가능한 한 매크로에서 벗어나는 것이 좋습니다. 이와 같은 기능이 필요한 경우 매크로를 과도하게 사용하고있을 가능성이 있습니다.
에 가장 큰 관련하여 데렉 레드베터 , 데이비드 Sorkovsky , Syphorlate 함께 의해 빈 매크로 인자를 감지하는 독창적 인 방법으로 자신의 답변을, 옌스 Gustedt 에서
https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
마침내 나는 모든 트릭을 통합하는 논의를 내놓았습니다. 그래서 해결책은
- 함수 오버로딩을 달성하기 위해 표준 C99 매크로 만 사용하고 GCC / CLANG / MSVC 확장은 포함하지 않습니다 (즉,
, ##__VA_ARGS__
GCC / CLANG 에 대한 특정 에 의해 쉼표 삼키기 및##__VA_ARGS__
MSVC 에 대한 암시 적 삼키기 ). 따라서--std=c99
원하는 경우 컴파일러에 누락 된 부분 을 자유롭게 전달하십시오 =) - 에 맞게 추가 필요로 확장하는 경우 인수가 무제한 일뿐 만 아니라 인수 가 무제한 인 경우 에도 작동 합니다.
합리적으로 크로스 플랫폼 에서 작동 하고 최소한의 테스트
- GNU / Linux + GCC (CentOS 7.0 x86_64의 GCC 4.9.2)
- GNU / Linux + CLANG / LLVM , (CentOS 7.0 x86_64의 CLANG / LLVM 3.5.0)
- OS X + Xcode , (OS X Yosemite 10.10.1의 XCode 6.1.1)
- Windows + Visual Studio , (Windows 7 SP1 64 비트의 Visual Studio 2013 업데이트 4)
lazies의 경우 소스를 복사 한 게시물의 맨 마지막으로 건너 뛰십시오. 아래는 __VA_ARGS__
저와 같은 일반적인 솔루션을 찾는 모든 사람들을 돕고 영감을주는 자세한 설명 입니다. =)
방법은 다음과 가변합니다. 우선 그것을 명명은 사용자에게 표시 오버 "기능"정의을 create
하고 관련 실제 함수 정의 realCreate
및 다른 인자 수와 매크로 정의는 CREATE_2
, CREATE_1
, CREATE_0
, 아래와 같이
#define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
#define CREATE_2(x, y) realCreate(x, y)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_0() CREATE_1(0)
MACRO_CHOOSER(__VA_ARGS__)
부분은 매크로 정의 이름을 해결하고, 둘째 (__VA_ARGS__)
부분은 매크로를 포함한다. 에 대한 사용자의 호출 그래서 create(10)
로 확인 CREATE_1(10)
의 CREATE_1
부분에서 유래 MACRO_CHOOSER(__VA_ARGS__)
하고, 일부 (10)
는 두 번째에서 온다 (__VA_ARGS__)
.
는 경우 MACRO_CHOOSER
, 그 트릭을 사용 비어, 다음 사용 __VA_ARGS__
가능한 매크로 호출로 연결됩니다.
NO_ARG_EXPANDER __VA_ARGS__ () // simply shrinks to NO_ARG_EXPANDER()
독창적 으로이 매크로 호출 결과를 다음과 같이 정의 할 수 있습니다.
#define NO_ARG_EXPANDER() ,,CREATE_0
두 개의 쉼표는 곧 설명됩니다. 다음 유용한 매크로는
#define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
그래서의 부름
create();
create(10);
create(20, 20);
실제로 확장됩니다
CHOOSE_FROM_ARG_COUNT(,,CREATE_0)();
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 10 ())(10);
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 20, 20 ())(20, 20);
매크로 이름에서 알 수 있더라도 나중에 인수 수를 계산해야합니다. 여기에 또 다른 트릭이 있습니다. 전처리 기는 단순한 텍스트 교체 만 수행합니다. 괄호 안에있는 쉼표의 수만으로 매크로 호출의 인수 수를 추론합니다. 쉼표로 구분 된 실제 "인수"는 유효한 구문 일 필요는 없습니다. 모든 텍스트가 될 수 있습니다. 즉, 위의 예 NO_ARG_EXPANDER 10 ()
에서 중간 호출에 대해 1 개의 인수로 계산됩니다. NO_ARG_EXPANDER 20
및 20 ()
바닥 바닥 호출 2 개 인자로 계산됩니다.
다음 도우미 매크로를 사용하여 추가 확장하면
##define CHOOSE_FROM_ARG_COUNT(...) \
FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
#define FUNC_RECOMPOSER(argsWithParentheses) \
FUNC_CHOOSER argsWithParentheses
후행은 ,
후 CREATE_1
작업 주위 GCC / 꽝에 대한 것을 말하는 (위양성) 오류 ISO C99 requires rest arguments to be used
무시 이다 통과 할 때 -pedantic
컴파일러에 있습니다. 은 FUNC_RECOMPOSER
MSVC에 대한 해결 방법, 또는 매크로 호출의 괄호 안의 인수의 수 (즉, 쉼표)를 셀 수 없다. 결과는 다음과 같이 추가로 해결됩니다.
FUNC_CHOOSER (,,CREATE_0, CREATE_2, CREATE_1, )();
FUNC_CHOOSER (NO_ARG_EXPANDER 10 (), CREATE_2, CREATE_1, )(10);
FUNC_CHOOSER (NO_ARG_EXPANDER 20, 20 (), CREATE_2, CREATE_1, )(20, 20);
독수리 눈을 가진 사람처럼 우리가 필요로하는 마지막 단계는 표준 인수 계수 트릭을 사용하여 원하는 매크로 이름을 최종적으로 선택하는 것입니다.
#define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
결과를
CREATE_0();
CREATE_1(10);
CREATE_2(20, 20);
그리고 확실히 원하는 실제 함수 호출을 제공합니다.
realCreate(0, 0);
realCreate(10, 10);
realCreate(20, 20);
더 나은 가독성을 위해 명령문을 재정렬하여 모두 합치면 2- 인수 예제 의 전체 소스 는 다음과 가변합니다.
#include <stdio.h>
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
#define CREATE_2(x, y) realCreate(x, y)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_0() CREATE_1(0)
#define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(...) FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
#define NO_ARG_EXPANDER() ,,CREATE_0
#define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
#define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
int main()
{
create();
create(10);
create(20, 20);
//create(30, 30, 30); // Compilation error
return 0;
}
복잡하고 추악하며 API 개발자에게 부담이되는 C / C ++ 함수의 언급 변수를 오버로딩하고 미친 사람들에게 설정하는 솔루션이 있습니다. 앞으로 나오는 오버로드 된 API의 사용은 매우 즐겁고 즐거워입니다. =)
이 접근 방식을 더 단순화 할 수있는 경우 다음 주소로 알려주십시오.
https://github.com/jason-deng/C99FunctionOverload
이 작품을 발표하도록 영감을주고 준 모든 훌륭한 사람들에게 다시 한 번 감사드립니다! =)
Visual C ++에서 작동하는 일부 VA_NARGS 솔루션을 고통스럽게 검색하는 사람을 위해. 다음 매크로는 Visual C ++ Express 2010에서 완벽하게 작동했습니다 (매개 변수도 0입니다!).
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,N,...) N
#define VA_NUM_ARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS(...) bool(#__VA_ARGS__) ? (VA_NUM_ARGS_IMPL_((__VA_ARGS__, 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
요청한 경우 다음을 수행 할 수 있습니다.
//macro selection(vc++)
#define SELMACRO_IMPL(_1,_2,_3, N,...) N
#define SELMACRO_IMPL_(tuple) SELMACRO_IMPL tuple
#define mymacro1(var1) var1
#define mymacro2(var1,var2) var2*var1
#define mymacro3(var1,var2,var3) var1*var2*var3
#define mymacro(...) SELMACRO_IMPL_((__VA_ARGS__, mymacro3(__VA_ARGS__), mymacro2(__VA_ARGS__), mymacro1(__VA_ARGS__)))
그것은 vc라고 저에게 맞는군요. 그러나 매개 변수가없는 경우에는 작동하지 않습니다.
int x=99;
x=mymacro(2);//2
x=mymacro(2,2);//4
x=mymacro(2,2,2);//8
gcc
/ varargs 매크로를g++
지원 하지만 그것이 표준이라고 생각하지 않습니다.
#include <stdio.h>
#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)
#define PP_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 PP_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
#define PP_CONCAT(a,b) PP_CONCAT_(a,b)
#define PP_CONCAT_(a,b) a ## b
#define THINK(...) PP_CONCAT(THINK_, PP_NARG(__VA_ARGS__))(__VA_ARGS__)
#define THINK_0() THINK_1("sector zz9 plural z alpha")
#define THINK_1(location) THINK_2(location, 42)
#define THINK_2(location,answer) THINK_3(location, answer, "deep thought")
#define THINK_3(location,answer,computer) \
printf ("The answer is %d. This was calculated by %s, and a computer to figure out what this"
" actually means will be build in %s\n", (answer), (computer), (location))
int
main (int argc, char *argv[])
{
THINK (); /* On compilers other than GCC you have to call with least one non-default argument */
}
면책 조항 : 대부분 무해합니다.
그것은 실제로 전처리 기가 것이 아닙니다.
즉, 어느 정도의 가독성으로 심각하게 까다로운 매크로 프로그래밍 영역에 좀 더 부스트 전 처리기 라이브러리를 살펴보아야 합니다 . 결국 튜링과 완전히 호환되는 프로그래밍 수준 (전 처리기, 템플릿 메타 프로그래밍 및 기본 수준 C ++)이 세 가지 모두 C ++가 아닐 것입니다!
#define MY_MACRO_3(X,Y,Z) ...
#define MY_MACRO_2(X,Y) MY_MACRO(X,Y,5)
#define MY_MACRO_1(X) MY_MACRO(X,42,5)
호출 시점에서 얼마나 많은 인수를 거기에서 실제로 오버로딩 할 필요가 없습니다.
Derek Ledbetter 코드의 더 간결한 버전 :
enum
{
plain = 0,
bold = 1,
italic = 2
};
void PrintString(const char* message = NULL, int size = 0, int style = 0)
{
}
#define PRINT_STRING(...) PrintString(__VA_ARGS__)
int main(int argc, char * const argv[])
{
PRINT_STRING("Hello, World!");
PRINT_STRING("Hello, World!", 18);
PRINT_STRING("Hello, World!", 18, bold);
return 0;
}
도서관 BOOST_PP_OVERLOAD
에서 사용할 수 있습니다 boost
.
공식 부스트 문서의 예 :
#include <boost/preprocessor/facilities/overload.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#define MACRO_1(number) MACRO_2(number,10)
#define MACRO_2(number1,number2) BOOST_PP_ADD(number1,number2)
#if !BOOST_PP_VARIADICS_MSVC
#define MACRO_ADD_NUMBERS(...) BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__)
#else
// or for Visual C++
#define MACRO_ADD_NUMBERS(...) \
BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY())
#endif
MACRO_ADD_NUMBERS(5) // output is 15
MACRO_ADD_NUMBERS(3,6) // output is 9
필요한 것에 따라 매크로를 사용 하여 var args 로 수행 할 수 있습니다. 이제 선택적 매개 변수 나 매크로 오버로딩은 없습니다.
끔찍한 매크로 몬스터의 열렬한 팬으로서 Jason Deng의 답변을 확장하고 실제로 사용할 수 있도록 만들고 싶었습니다. (더 좋든 나쁘 든간에.) 원본은 새 매크로를 만들 때마다 큰 알파벳 수프를 수정해야하기 때문에 사용하기에 그리 좋지 않으며 다른 양의 인수가 필요한 경우 더 나쁩니다.
그래서 다음과 같은 기능을 갖춘 버전을 만들었습니다.
- 0 인수 케이스 작동
- 지저분한 부분을 수정하지 않고 1 ~ 16 개의 인수
- 더 많은 매크로 함수를 작성하기 쉽습니다.
- gcc 10, clang 9, Visual Studio 2017에서 테스트되었습니다.
현재는 최대 16 개의 인수를 설정했지만 더 필요한 경우 (정말 지금? 그냥 어리석은 것 같습니다 ...) FUNC_CHOOSER 및 CHOOSE_FROM_ARG_COUNT를 편집 한 다음 NO_ARG_EXPANDER에 쉼표를 추가 할 수 있습니다.
구현에 대한 자세한 내용은 Jason Deng의 훌륭한 답변을 참조하십시오.하지만 여기에 코드를 넣겠습니다.
#include <stdio.h>
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
// This part you put in some library header:
#define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16, ...) _f16
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(F, ...) FUNC_RECOMPOSER((__VA_ARGS__, \
F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\
F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, ))
#define NO_ARG_EXPANDER(FUNC) ,,,,,,,,,,,,,,,,FUNC ## _0
#define MACRO_CHOOSER(FUNC, ...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC))
#define MULTI_MACRO(FUNC, ...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__)
// When you need to make a macro with default arguments, use this:
#define create(...) MULTI_MACRO(CREATE, __VA_ARGS__)
#define CREATE_0() CREATE_1(0)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_2(x, y) \
do { \
/* put whatever code you want in the last macro */ \
realCreate(x, y); \
} while(0)
int main()
{
create();
create(10);
create(20, 20);
//create(30, 30, 30); // Compilation error
return 0;
}
위의 예제 (Derek Ledbetter, David Sorkovsky 및 Joe D) 중 매크로로 인수를 계산하는 것은 Microsoft VCC 10을 사용하여 저에게 효과적이었습니다. __VA_ARGS__
인수는 항상 단일 인수로 간주됩니다 (토큰 화 ##
여부에 관계 없음). 이러한 예제가 의존하는 인수 이동은 작동하지 않습니다.
따라서 위의 다른 많은 사람들이 언급했듯이 짧은 대답 : 아니요, 매크로를 오버로드하거나 선택적 인수를 사용할 수 없습니다.
참고 URL : https://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros
'IT' 카테고리의 다른 글
stdClass () [duplicate]를 사용하여 배열을 객체로 변환하는 방법 (0) | 2020.08.24 |
---|---|
활동이 전경 또는 보이는 배경에 있는지 확인하는 방법은 무엇입니까? (0) | 2020.08.24 |
Android 휴대 전화 애플리케이션을 세로 모드로 잠금 (0) | 2020.08.24 |
Intellij에서 생성 된 버전 UID를 생성하는 방법 (0) | 2020.08.24 |
RecyclerView- 특정 위치에서 항목 위로 부드럽게 스크롤하는 방법은 무엇입니까? (0) | 2020.08.24 |