2016-11-06 12 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); 
} 

:最も簡単な1は、3D空間内の座標の数が2つの構造体を定義してカウント例がばかげていると、より複雑な機能にはより意味をなさない。

私は_Genericを使用して、トリプレットのintまたはstructを渡すと考えました。

int boxes_inside_cc(const coord min, const coord max); 
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); 
int boxes_inside_ii(const int minx, const int miny, const int minz, const int maxx, const int maxy, const int maxz); 

#define arg1(a, ...) (a) 
#define arg2(a, b ...) (b) 
#define arg4(a, b, c, d, ...) (d) 

#define boxes_inside(...) _Generic(arg1(__VA_ARGS__), \ 
     coord: _Generic(arg2(__VA_ARGS__), coord: boxes_inside_cc, int: boxes_inside_ci) \ 
     int: _Generic(arg4(__VA_ARGS__), coord: boxes_inside_ic, int: boxes_inside_ii) \ 
    )(__VA_ARGS__) 

「選択されていない選択肢の表現は決して評価されないので、これはうまくいくと思いました。 (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は、おそらくブーストプリプロセッサライブラリがとにかく近いものです。しかし、それは私が最初にそれを使用して_Genericの制限でうんざりされ、私は何か愚かなものを見逃していないのだろうかと思っている以上です... – Cimbali

+0

私はこのアプローチが動作しないと思う;ジェネリックのすべてのブランチは、選択されていなくても制約違反がない必要があります。 –

答えて

1

ここでは、実際には洗練された解決策ではないので、実際に満足いくものではありませんが、ここでコメントで取り上げた内容を説明します。

  • まず、必要_Genericを使用して、引数の許容数、であるすべてのXためboxes_inside_Xを定義します。
  • その後、引数の数を貼り付けて(またはQuentinのようにBoost.PPを使用して)マクロをオーバーロードします。間違った引数の数、または
  • expected ‘coord {aka const struct <anonymous>}’ but argument is of type ‘int’ため
/* 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’種類がある場合違う。
関連する問題