2017-04-16 1 views
0

C++에서 가변 매크로 require at least one argument for the '...'. 다음과 같은 함수를 고려하십시오. FOO(a, b, ...); 이러한 호출이 정확하고 경고없이 수행되기를 원한다면 어떻게해야합니까? FOO(5, 4, "gamma"); FOO(5, 4); 나는 --pedantic 플래그를 사용하고 있으므로 경고를 그냥 억제하는 것은 옵션이 아닙니다.Variadic 매크로 경고

두 번째 것은 위에서 언급 한 컴파일 타임 경고를 제공합니다. 나는 이것을 다음과 같이 고려했다.

정의를 FOO(a, ...);으로 변경하고 __VA_ARGS__ 변수 (...를 의미 함)를 b (있는 경우)으로 나눕니다. 그래서 함수 호출은 다음과 같이 보일 것입니다 : FOO(5, "4gamma");FOO(5, "4"); 이것은 생각합니다. 왜냐하면 분할은 효율적이지 않고 함수 선언은 필수적이긴하지만 b 인수를 필요로하지 않기 때문입니다.

경고없이 컴파일하는 더 좋은 방법이 있습니까?

+3

왜 매크로를 사용하고 있습니까? 당신이 해결하려고하는 실제 문제는 무엇입니까? –

+0

variadic 함수 템플릿이 솔루션입니다. – DeiDei

+0

@DeiDei 기능 템플릿을 자세히 설명해 주시겠습니까? – FigsHigs

답변

3

가능한 모든 변수 함수 또는 함수 템플릿을 사용해야한다고 동의하지만 매크로를 사용하여 수행 할 수있는 작업과 수행 할 수없는 작업에 대한 오해를 보여주기 때문에이 답변에서 함수를 가장 할 것입니다. 옵션이 아닙니다.

FOO(a, ...);의 정의를 변경하고있는 경우에 나머지, b로 (... 약자)를 __VA_ARGS__ 변수를 분할하고.

예. FOO(5, "4gamma");FOO(5, "4");

번호가 FOO(5, 4, "gamma");FOO(5, 4);로 호출을 계속 : 같은

그래서 함수 호출이 보일 것이다. 첫 번째 경우 __VA_ARGS__4, "gamma"입니다. 두 번째 경우 __VA_ARGS__4입니다.

전처리 기에서 , "gamma"을 추출해야하는 경우 전처리 기가이를 수행 할 수 있습니다. 그것은 매개 변수의 양에 상한이 필요합니다,하지만 당신은 당신이 좋아하는 어떤 숫자로 이것을 증가시킬 수 있습니다. 그래도 추한 데. __VA_ARGS__ 더 쉼표를 포함하지

경우, 추출은 간단하다 : 당신이 __VA_ARGS__이 적어도 하나의 쉼표가 알고 있다면

#define COMMA_TRAILING_ARGS_0(a) 

, 당신은

#define COMMA_TRAILING_ARGS_1(a, ...) , __VA_ARGS__ 

을 사용할 수 있습니다 그리고 당신은 감지 할 수있는 다음의 어느에 매크로 인수의 특정 상한까지 사용 :

#define ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16 
#define HAS_COMMA(...) ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,) 

결합 :

#define COMMA_TRAILING_ARGS_0(a) 
#define COMMA_TRAILING_ARGS_1(a, ...) , __VA_ARGS__ 

#define ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16 
#define HAS_COMMA(...) ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,) 

#define CONCAT(a, b) a ## b 
#define CONCAT_(a, b) CONCAT(a, b) 

#define FOO(a, ...) BAR(a CONCAT_(COMMA_TRAILING_ARGS_, HAS_COMMA(__VA_ARGS__)) (__VA_ARGS__)) 

FOO(5, 4, x, q); // expands to BAR(5, x, q); 
FOO(5, 4, "gamma"); // expands to BAR(5, "gamma"); 
FOO(5, 4);   // expands to BAR(5); 
2
매크로 악마와가
  • 두 개의 매크로를 정의 할 수 있습니다 템플릿 또는 뭔가로 대체하기 때문에이 매크로 제거 할 수
  • +0

    하지만 그건 내가 'FOO (5, 4); FOOs (5, 4, "gamma");는 약간의 차이가 있습니다. – FigsHigs

    1

    내가 특정 문제를 이해하지 않습니다 (당신이 GCC 또는 호환 컴파일러를 사용하고 있다고 가정), 그러나 당신이 보여준 것과,이 두 오버로드 기능을 사용하는 것이 훨씬 쉽게 사용할 수 있습니다.

    void foo(int, int); 
    void foo(int, int, const std::string&); 
    
    foo(3, 4); // calls first 
    foo(3, 4, "hello"); // calls second 
    

    또는 어쩌면 : 한편

    void foo(int, int, const std::string& = ""); 
    

    사용할 수있는 경우 C++ 11 :

    template<typename... Args> 
    void foo(int, int, const Args&... args); // google variadic templates 
    

    매개 변수 팩 (args가) 제로 또는 구성 될 수 있습니다 more 인수.