2016-04-08 16 views
2

以下のプリプロセッサマクロがあります。プリプロセッサマクロを貪欲にする方法は?

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {}; 
#else 
# define DOCUMENTED_TYPEDEF(x, y) typedef x y; 
#endif 

Xが非テンプレートであるか唯一のテンプレートパラメータを持っているとき、それは素晴らしい作品:そのDoxygenのは、C++およびいくつかのテンプレートのtypedefとのトラブルを持っているので、Doxygenのドキュメントを支援するために使用。 Xは、複数のパラメータを持つテンプレートである場合は、:

DOCUMENTED_TYPEDEF(Foo<R,S>,Bar); 

文字列がFoo<Rに分割し、S>,Bar(と、それはドキュメントを生成しません)されているため、その後、それはコンパイルエラーになります。

プリプロセッサマクロを貪欲にするにはどうすればよいですか?

答えて

3

プリプロセッサの引数の解析方法を変更する方法はありません。括弧内にないカンマは、常にマクロ引数を区切ります。内側の括弧は、マクロの展開に表示されるため、それは大丈夫だ場合は、行うことができるかもしれません何

DOCUMENTED_TYPEDEF((Foo<R,S>), Bar); 

もちろんこれだけ作品です。これはあなたが表示している文脈で問題を引き起こす場合、私は頭の上から覚えていません。

それはC99可変引数マクロを必要とするためにOKなら、あなたは余分な括弧を取り除くためにそれらを使用することができます:

#define STRIP_PARENS(...) __VA_ARGS__ 
#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(x, y) class y : public STRIP_PARENS x {}; 
#else 
# define DOCUMENTED_TYPEDEF(x, y) typedef STRIP_PARENS x y; 
#endif 

DOCUMENTED_TYPEDEF((Foo<R,S>), Bar); 

が、今、あなたは常には、最初の引数は括弧の余分なペアを配置する必要がありますDOCUMENTED_TYPEDEFに

+0

私は左の引数Xは、宣言指定の位置に置かれているので、それは、問題が発生します疑います。 CおよびC++スタイル宣言では、宣言指定子はオプションのかっこを使用しません。しかしながら、宣言子は: 'int x;'と 'int(x);'は同じことです。 '(int)x;'はキャスト式のように見えます。 – Kaz

+0

@ Kaz C99可変マクロを実装するコンパイラのみをサポートするテンプレートパラメータ、*と*を含むかもしれない引数の周りに*常に*カッコを入れることができますか?もしそうなら、機能するハックがあります。 – zwol

4

次のようなつもりじゃない:

#define COMMA , 

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {}; 
#else 
# define DOCUMENTED_TYPEDEF(x, y) typedef x y; 
#endif 

DOCUMENTED_TYPEDEF(Foo<R COMMA S>,Bar) 

テスト:任意の置換が行われる前に

 
$ gcc -E comma-macro.c 
# 1 "comma-macro.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "comma-macro.c" 
# 9 "comma-macro.c" 
typedef Foo<R , S> Bar; 

マクロ引数リストは括弧とカンマのために解析されます。 x引数でCOMMAが置換され、マクロ本体にxが代入されます。その時、議論が破られました。 COMMAがカンマ区切り記号トークンに置き換えられていることは関係ありません。しかし、そのコンマは、そのマクロによって生成されたマクロ呼び出しで発生する別々の引数なので、それらを保護する必要がある場合は、もっと狂ったことが必要です。

あなたは関数のようなマクロの後ろCOMMAを隠すことができ、PAIRを言う:一見

#define COMMA , 

#define PAIR(A, B) A COMMA B 

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {}; 
#else 
# define DOCUMENTED_TYPEDEF(x, y) typedef x y; 
#endif 

DOCUMENTED_TYPEDEF(PAIR(Foo<R, S>), Bar) 

それがより魅力的ですが、欠点は、おそらくあります。それはもっと難解です。読者は、PAIRの後ろにセマンティクスがあるのだろうか? COMMAはあまりにも曖昧すぎてセマンティクスを持っていませんが、その目的は戦闘傷跡がプリプロセッサと戦っている人にはすぐに明らかです。

についてPAIRについては、私たちはそれを隠すことができ、Zwolの答えのような構文で終わることがあります。しかし、我々はDOCUMENTED_TYPEDEFの複数の変種が必要です。

また、ところで、のは、マクロの右側に必要とされていない無用COMMAを落としてみましょう:それはC99スタイル可変引数マクロでなんとかかもしれよう

#define PAIR(A, B) A, B 

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF_2(x2, y) class y : public PAIR x2 {}; 
#else 
# define DOCUMENTED_TYPEDEF_2(x2, y) typedef PAIR x2 y; 
#endif 

DOCUMENTED_TYPEDEF_2((<R, S>), Bar) 
 
$ gcc -std=c90 -E -Wall -pedantic comma-macro.c 
# 1 "comma-macro.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "comma-macro.c" 
# 11 "comma-macro.c" 
typedef <R, S> Bar; 

これが見えます。しかし、これはC++であることは言うまでもなく、コメントで説明されている移植性の要件に違反する可能性があります。将来の訪問者のために:

#define PNEUMATIC_COMMA_GUN(A, ...) A, ## __VA_ARGS__ 

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(xv, y) class y : public PNEUMATIC_COMMA_GUN xv {}; 
#else 
# define DOCUMENTED_TYPEDEF(xv, y) typedef PNEUMATIC_COMMA_GUN xv y; 
#endif 

DOCUMENTED_TYPEDEF((<R, S, T, L, N, E>), Bar) 
 
$ gcc -std=c99 -E -Wall -pedantic comma-macro.c 
# 1 "comma-macro.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "comma-macro.c" 
# 9 "comma-macro.c" 
typedef <R, S, T, L, N, E> Bar; 
+0

これは醜いです。私はいつも貪欲でない試合を数えることができますか?もしそうなら、私は 'X'と' Y'を逆にすることを考えています。トリッキーな点は、よく定義されているものと実装が定義されているもののようです。ほぼすべてのプラットフォームのコンパイラで作業し、1990年代に戻る必要があります。その特別な地獄です。 – jww

+0

プリプロセッサは、カッコで囲まれていないコンマでマクロ引数リストを改行します。 (カッコのトークンを数えてバランスをとる)角括弧、中かっこまたは角かっこは認識されません。それらはコンマに保護を提供しません。それは貪欲とはほとんど関係がありません。 – Kaz

+0

移植性については、私はC90プリプロセッサ構文のみを使用しました。 – Kaz