2017-04-16 15 views
0

C++では、可変マクロrequire at least one argument for the '...'。関数を考えてみましょう:FOO(a, b, ...);これらの呼び出しの両方を正確にし、警告なしにしたい場合はどうすればよいでしょうか? FOO(5, 4, "gamma"); FOO(5, 4);私は--pedanticフラグを使用していますので、警告を抑制することはオプションではありません。Variadicマクロ警告

もう1つは、上記のコンパイル時の警告です。

定義をFOO(a, ...);に変更し、__VA_ARGS__変数(これは...の略)をbに分割し、残りの部分があればそれを分割します。したがって、関数呼び出しは次のようになります:FOO(5, "4gamma");FOO(5, "4");分割は効率的ではなく、関数宣言には引数が必要ですが、b引数は必要ないため、これは良い選択ではありません。

警告のないコンパイル方法はありますか?

+3

なぜマクロを使用していますか?あなたが解決しようとしている実際の問題は何ですか? –

+0

バリデーショナル関数テンプレートがあなたのソリューションです。 – 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"です。 2番目のケースでは、__VA_ARGS__4です。

前者から, "gamma"を抽出する必要がある場合は、プリプロセッサで行うことができます。パラメータの量には上限が必要ですが、これを任意の数に増やすことができます。しかし、それは醜いです。

__VA_ARGS__は何のカンマが含まれていない場合、抽出が簡単です:

#define COMMA_TRAILING_ARGS_0(a) 

あなたは__VA_ARGS__は、少なくとも一つのカンマが入っていることがわかっている場合は、あなたが

#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
  • マクロは悪であり、あなたは、2つのマクロを定義することができますテンプレートまたは何か他のもの
  • に置き換えるので、あなたがこのマクロを取り除くことができます:FOOsを - 多くの引数とFOOで - わずか2 argumets
  • であなたはgcc ##__VA_ARGS__ extension(あなたがGCCまたは互換性のあるコンパイラを使用していると仮定して)
+0

しかし、それは私が 'FOO(5、4)にする必要があることを意味します。 FOOs(5、4、 "gamma");は、私が望むものとは少し異なるものです。 – FigsHigs

1

を使用することができます私はあなたの特定の問題を理解していない、しかし、あなたが示されてきたものから、それは2つのオーバーロードされた関数を使用する方がはるかに簡単です。

でも
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を)もっと引数。