2016-11-06 6 views
3

일부 C 코드에 구문 상 귀족을 추가하려는 이상한 상황이 있음을 알고 있습니다. 나는 구조체 인 숫자의 삼중 항을가집니다._ 최소한의 인수 개수를 넘는 일반 매개 변수

typedef struct {int x, y, z} coord; 

이제 인수와 같은 구조체 2 개를 사용하는 함수가 있습니다. 나 자신이 꽤 정기적으로 내가

coord foo; 
/* initialize foo with something */ 
int n = boxes_inside((coord){.x = 0, .y = 0, .z = 0}, foo); 

신경 끄시이 매우 추한 찾을 고정 인수로 호출 찾을

static inline int boxes_inside(const coord min, const coord max) 
{ 
    return (1 + max.x - min.x) * (1 + max.y - min.y) * (1 + max.z - min.z); 
} 

: 가장 간단한 하나는 3D 공간 내의 좌표의 수는 두 개의 구조체를 정의 계산 예를 들어 어리석은 일이라면, 더 복잡한 기능에 더 많은 의미가 있습니다.

나는 _Generic을 사용하여 세 쌍의 int 또는 struct를 전달할 것이라고 생각했습니다.

"선택되지 않은 선택 항목의 표현은 평가되지 않기 때문에 괜찮을 것"이라고 생각했습니다. (ref)하지만이 매크로는 done after preprocessing이므로 선택한 매크로가 선택되지 않은 경우에도 모든 매크로가 계속 확장됩니다. 특히

, 지금 다음 호출 할 경우 :

coord min, max; 
/* stuff */ 
int n = boxes_inside(min, max); 

를 내가 얻을 실제로이보다 arg4(__VA_ARGS__) 시도가 _Generic의이 지점은 나중에 평가되지 않습니다에도 불구하고, 더 많은 매개 변수를 확장하는 문제 에.

#define boxes_inside_(a, b, c, d, ...) _Generic((a), \ 
     coord: boxes_inside_ii(a, b, c, d.x, d.y, d.z), \ 
     int: boxes_inside_ii(a, b, c, d, __VA_ARGS__) \ 
    ) 

#define boxes_inside(a, ...) _Generic((a), \ 
     coord: boxes_inside_(a.x, a.y, a.z, __VA_ARGS__) \ 
     int: boxes_inside_(a, __VA_ARGS__) \ 
    ) 

그러나이 당연히 같은 이유로 실패 :

그래서 나는 그 때, 항상 충분한 인자를 가지고있는 구조체를 확장하려고 boxes_inside(min, max) 특정 여전히에 boxes_inside_(min max)로 확장에서 두 가지 다른 매크로를 확장 우리가 이미 알고있는 지점은 사용되지 않을 것입니다.

이렇게 방법이 있습니까? 또는 최소한 사용할 수있는 매개 변수 수를 초과하는 매개 변수를 테스트하려는 경우 _Generic 식은 기본적으로 쓸모가 없습니까?

+2

[Boost.PP] (http://www.boost.org/doc/libs/master/libs/preprocessor/doc/ref/overload.html) 마술을이 문제와 관련 시켜서 제안하는 것이 거의 두려워요. 물건이지만, 당신은 커피 기계이므로 아마 당신이하는 일을 알 것입니다. – Quentin

+0

@Quentin 저는 항상 [인수의 개수에 매크로 오버로드] (https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments)부터 시작할 수 있습니다. _Generic은 아마도 부스트 전 처리기 라이브러리가 수행하는 것과 거의 유사 할 것입니다. 하지만 그것은 처음 사용했을 때 제네릭의 한계에 당황스럽고, 내가 바보 같은 것을 간과하지 않았는지 궁금해하는 것이 더 낳습니다. – Cimbali

+0

나는이 접근법이 작동하지 않는다고 생각합니다. generic의 모든 브랜치는 선택되지 않아도 제약 조건 위반이 없어야합니다. –

답변

1

글쎄, 여기에 코멘트에서 언급 한 내용은 실제로 만족 스럽지는 않지만 실제로는 우아한 해결책이 아니기 때문에 여기에 설명되어 있습니다.

  • 먼저 필요한 _Generic을 사용 인수의 허용 개수 인 모든 X위한 boxes_inside_X를 정의한다.
  • 그런 다음 인수 개수를 붙여 넣거나 (Quentin으로 제안 된대로 Boost.PP을 사용하여) 매크로를 오버로드하십시오.
/* macros that can be reused (possibly with more arguments) */ 
#define paste2(a, b) a ## b 
#define paste(a, b) paste2(a, b) 
#define get_seventh(_1, _2, _3, _4, _5, _6, this_one, ...) this_one 
#define get_suffix(...) get_seventh(__VA_ARGS__, _6, _5, _4, _3, _2, _1) 

/* define all variants with number of arguments suffix */ 
int boxes_inside_2(const coord min, const coord max); 
int boxes_inside_6(const int minx, const int miny, const int minz, const int maxx, const int maxy, const int maxz); 

/* make it a _Generic, if several functions have the same number of arguments */ 
int boxes_inside_ci(const coord min, const int maxx, const int maxy, const int maxz); 
int boxes_inside_ic(const int minx, const int miny, const int minz, const coord max); 
#define boxes_inside_4(a, ...) _Generic((a),\ 
     coord: boxes_inside_ci) \ 
     int: boxes_inside_ic) \ 
    )(__VA_ARGS__) 

/* make macro call itself with the number of arguments pasted after it */ 
#define boxes_inside(...) paste(boxes_inside, get_suffix(__VA_ARGS__))(__VA_ARGS__) 

이 방법의 거꾸로 유형이 경우 인수의 잘못된 번호에 대한 예를

  • warning: implicit declaration of function ‘boxes_inside_3’을 위해 합리적으로 읽을 수있는 오류 메시지를 받거나
  • expected ‘coord {aka const struct <anonymous>}’ but argument is of type ‘int’이다 잘못된.