C ++ 매크로를 사용하는 선택적 매개 변수


105

C ++ 매크로로 선택적 매개 변수를 얻는 방법이 있습니까? 어떤 종류의 과부하도 좋을 것입니다.


1
C도 동일 : stackoverflow.com/questions/11761703/… 전처리 기가 기본적으로 동일하므로 동일해야합니다. stackoverflow.com/questions/5085533/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

아마도 함수 오버로드, 기본 매개 변수, 가변 템플릿 또는 명명 된 매개 변수 관용구가 당신이 찾고
smoothware

실제 솔루션, 말을하지 않는 낮은-upvoted 하나 고도로 upvoted 사람에게 선택한 답을 업데이트하십시오No you can't
알버트 렌쇼

답변:


156

여기에 한 가지 방법이 있습니다. 인수 목록을 두 번 사용하여 먼저 도우미 매크로의 이름을 만든 다음 해당 도우미 매크로에 인수를 전달합니다. 표준 트릭을 사용하여 매크로에 대한 인수 수를 계산합니다.

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;
}

이렇게하면 작성자가 아닌 매크로 호출자가 더 쉽게 수행 할 수 있습니다.


1
이것은 꽤 멋지지만 PRINT_STRING 만하면 작동하지 않을 것이라고 생각합니다. 이 경우 기본 인쇄물이 없을 것입니다 (실제로 제가 활용하려는 경우입니다). 정말 멋지다면 여전히 +1.
Cenoc 2010-06-15

2
나를 위해 gcc에서 작동합니다 (매우 영리합니다!) :-) Visual Studio에서는 작동하지 않습니다. :-(
Tim Gradwell

3
@TimGradwell-MSVC 컴파일러의 버그로 인해 인정했지만 거의 10 년 동안 수정되지 않았습니다. 그러나 해결 방법 을 사용할 수 있습니다 .
BeeOnRope

영리하지만 'GET_4th_ARG'에서 진행중인 '푸시 아웃'작업 때문에 선택적 가변 매크로 인수에 대해서는 작동하지 않습니다.
searchengine27

그게 PRINT_STRING_MACRO_CHOOSER필요한가요? 내부 바디로 직접 교체하고이 모든 것을라고 부를 수 (__VA_ARGS__)있습니까?
Herrgott

85

그의 답변에 대해 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 : 저는 전문가가 아니기 때문에 의견 (좋음, 나쁨 또는 기타)을 듣게되어 매우 기쁩니다!


3
MACRO 이름으로 간주되는 선택된 인수를 # (파운드 기호)를 사용하여 문자열로 변환하고 예상 접두사와 처음 n 개의 문자를 비교하고 일치하는 항목이 없으면 정보를 인쇄하면 명확한 컴파일 오류가 발생할 수 있습니다. 오류.
AturSams

1
와우,이게 효과가 있는지 모르겠지만 적어도 아주 창의적입니다!
제한된 속죄

4
첫 번째 인수가 항상 비어있는 이유는 무엇입니까? 생략 할 수없는 이유 : XXX_X(,##__VA_ARGS__,` ... XXX_X (, XXX_4 (), XXX_3 (), XXX_2 (), XXX_1 (), XXX_0 ());`
rahman

2
비어있는 첫 번째 인수 (쉼표)가 중요합니다. 앞에 쉼표가있는 경우 ## __ VA_ARGS__ – ## __ VA_ARGS__가 아무것도 확장되지 않으면 쉼표를 제거합니다. 당신은 라인 만 6 매개 변수가 첫 번째 (인수)로 "가 ..."예에서 볼 수 있지만 나머지 7이 트릭 보장하지만 얻을 그 인수가없는 상황 일
데이비드 Sorkovsky

@Eric-이는 Microsoft 컴파일러의 버그로 인한 것이지만 이 질문 을 통해 해결 방법을 확인할 수 있습니다 .
BeeOnRope

31

C ++ 매크로는 C에서 변경되지 않았습니다. C에는 함수에 대한 오버로딩 및 기본 인수가 없었으므로 확실히 매크로에 대한 인수가 없었습니다. 따라서 귀하의 질문에 대답하십시오. 아니요, 이러한 기능은 매크로에 존재하지 않습니다. 유일한 옵션은 이름이 다른 여러 매크로를 정의하는 것입니다 (또는 매크로를 전혀 사용하지 않음).

참고로 : C ++에서는 일반적으로 가능한 한 매크로에서 벗어나는 것이 좋습니다. 이와 같은 기능이 필요한 경우 매크로를 과도하게 사용하고있을 가능성이 높습니다.


4
매크로를 "오버로드"할 수없는 이유는 고유 한 유형이 없기 때문입니다. 매크로는 단순히 확장됩니다.
mk12 2012-08-20

2
나는 가능한 한 적게 매크로를 사용하지만, 나는 추적 출력을 통해 디버깅하는 것은 같은 것들과 상당히 쉽게 얻을 수 있음을 발견 __FILE__하고 __LINE__이러한 ...
기독교 세브린

좋은 대답이 아닙니다. 이 좋은 답변입니다 stackoverflow.com/q/27049491/893406
v.oddou

조건부 컴파일 및 디버깅 / 로깅은 매크로가 정말 편리하고 합법적 인 도메인입니다. 모든 진지한 프로그래머는 그것을 알고 있습니다. 좋은 방법은 상수를 정의하기 위해 매크로를 사용하지 않고 컨테이너 템플릿을 만들기 위해 미친 C 레벨 코딩 작업을 수행하는 것에서 벗어나는 것입니다. C ++이 매크로에 더 많은 기능을 추가하기를 바랍니다. 템플릿과 직교합니다. 물론 가장 좋은 것은 도메인 특정 언어 (측면)를 위해 컴파일러에 생성기를 추가 할 수있는 코드 렛입니다.
Lothar

1
또한 매크로는 컴파일러보다 먼저 처리되기 때문에 매크로가 C ++ 언어 옵션과 완전히 다른 것이기 때문에 이것이 좋은 대답이 아니라고 생각합니다. 따라서 다른 작업을 수행 할 수 있으며 컴파일러 나 링커가 코드를 최적화해서는 안됩니다. 최적화가 아닐 수도 있기 때문입니다.
alabamajack

26

에 가장 큰 관련하여 데렉 레드베터 , 데이비드 Sorkovsky , Syphorlate 함께 의해 빈 매크로 인자를 감지하는 독창적 인 방법으로 자신의 답변을, 옌스 Gustedt 에서

https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/

마침내 나는 모든 트릭을 통합하는 무언가를 내놓았습니다. 그래서 해결책은

  1. 함수 오버로딩을 달성하기 위해 표준 C99 매크로 만 사용하고 GCC / CLANG / MSVC 확장은 포함하지 않습니다 (즉, , ##__VA_ARGS__GCC / CLANG 에 대한 특정 표현식 에 의한 쉼표 삼키기 및 ##__VA_ARGS__MSVC 에 대한 암시 적 삼키기 ). 그러니 실종 된 사람을 자유롭게 전달해--std=c99 원하는 경우 컴파일러에 을 =)
  2. 필요에 맞게 추가로 확장하는 경우 인수가 무제한 일뿐만 아니라 인수무제한 인 경우 에도 작동 합니다.
  3. 합리적으로 크로스 플랫폼 에서 작동 하며 최소한 테스트

    • 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 2020 () 각각 바닥 호출 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_RECOMPOSERMSVC에 대한 해결 방법, 또는 올바르게 매크로 호출의 괄호 안의 인수의 수 (즉, 쉼표)를 셀 수 없다. 결과는 다음과 같이 추가로 해결됩니다.

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

이 작품을 성취하도록 영감을주고 이끌어 준 모든 훌륭한 사람들에게 다시 한 번 감사드립니다! =)


3
이것을 3 개 또는 4 개의 기능으로 확장하는 방법은 무엇입니까?
Phylliida

@Phylliida ideone.com/jD0Hm5-0 ~ 5 개의 인수가 지원됩니다.
xx

9

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

나는군요unresolved external symbol _bool referenced in function _main
Avidan 보리 소프

예, 어떤 경우에는 발생할 수 있습니다. bool (#__ VA_ARGS__)? 런타임에 평가되므로 다른 매크로와 다릅니다. 귀하의 경우에 따라 코드의 해당 부분을 생략 할 수 있습니다.
Syphorlate 2013 년

2
실제로 완벽하게 작동 하는 pastebin.com/H3T75dcn으로 끝났습니다 (인수 0 개도 있음).
Avidan Borisov 2013 년

링크 주셔서 감사합니다. 그래도 sizeof를 사용하여 할 수 있지만 어떤 경우에는 작동하지 않았지만 원칙은 동일합니다 (부울 평가).
Syphorlate

실패한 경우 몇 가지 예를 들어 줄 수 있습니까?
Avidan Borisov 2013


5
#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 */
}

면책 조항 : 대부분 무해합니다.


코드에 오류가 있습니다. 하십시오 :%s/MY_MACRO_/THINK_/g:)
João Portela

또한, 그것은 ++ 제로 인수가 g을 사용하여 작동하지 않았다i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
주앙 포르텔

1
빈 토큰은 유효한 자리 표시 자이므로 가변 매크로에는 인수가 없습니다.
Paul Fultz II

3

그것은 실제로 전처리 기가 설계된 것이 아닙니다.

즉, 어느 정도의 가독성으로 심각하게 까다로운 매크로 프로그래밍 영역에 들어가려면 Boost 전 처리기 라이브러리를 살펴보아야 합니다 . 결국 튜링과 완전히 호환되는 프로그래밍 수준 (전 처리기, 템플릿 메타 프로그래밍 및 기본 수준 C ++)이 세 가지 없다면 C ++가 아닐 것입니다!


3
#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)

호출 시점에서 얼마나 많은 인수를 전달할 것인지 알고 있으므로 실제로 오버로딩 할 필요가 없습니다.


2
나는 실제로 기능의 존재에 대해 묻고있었습니다.
Cenoc 2010-06-15

3

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;
}

3

끔찍한 매크로 몬스터의 열렬한 팬으로서 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;
}

2

도서관 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

0

필요한 것에 따라 매크로를 사용 하여 var args 로 수행 할 수 있습니다. 이제 선택적 매개 변수 나 매크로 오버로딩은 없습니다.


-1

위의 예제 (Derek Ledbetter, David Sorkovsky 및 Joe D의) 중 매크로를 사용하여 인수를 계산하는 것은 Microsoft VCC 10을 사용하여 저에게 효과적이었습니다. __VA_ARGS__인수는 항상 단일 인수로 간주됩니다 (토큰 화## 여부에 관계 없음). 이러한 예제가 의존하는 인수 이동은 작동하지 않습니다.

따라서 위의 다른 많은 사람들이 언급했듯이 짧은 대답 : 아니요, 매크로를 오버로드하거나 선택적 인수를 사용할 수 없습니다.


1
가능하지만 C99 또는 C ++ 11에서만 가능합니다 (__VA_ARGS__가 있으므로). VC2010은 C89 / C ++ 03입니다 (C ++ 11의 일부 비트가 나타나기 시작하지만 아직은 아닙니다).
puetzk
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.