1. ホーム
  2. c++

[解決済み] C/C++マクロのカンマ

2022-09-11 10:08:02

質問

次のようなマクロがあるとします。

#define FOO(type,name) type name

のように使うことができます。

FOO(int, int_var);

しかし、必ずしもそのように単純なものではありません。

FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2

もちろん、できるはずです。

 typedef std::map<int, int> map_int_int_t;
 FOO(map_int_int_t, map_var); // OK

というのは、あまり人間工学的ではありません。さらに、型の非互換性にも対処しなければなりません。マクロでこれを解決する方法はないでしょうか?

どのように解決するのですか?

山括弧は比較演算子を表す(またはその中に現れる)こともあるため < , > , <=>= のように、角括弧内のカンマをマクロ展開で無視することはできません。 (これは角括弧と中括弧の問題でもあります。これらは通常、バランスの取れたペアとして発生しますが)。 マクロ引数を括弧で囲むことができます。

FOO((std::map<int, int>), map_var);

問題は、パラメータがマクロ展開の内部で括弧で囲まれたままであるため、ほとんどのコンテキストで型として読み取られないことです。

これを回避するための素晴らしいトリックは、C++では、関数型を使用して括弧で囲まれた型名から型名を抽出することができるということです。

template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
FOO((std::map<int, int>), map_var);

関数型の形成は余分な括弧を無視するので、型名にカンマが含まれない場合は括弧を付けても付けなくてもこのマクロを使用することができます。

FOO((int), int_var);
FOO(int, int_var2);

C言語では、型名が括弧の外にカンマを含むことができないので、もちろんこれは必要ない。 ですから、言語横断的なマクロの場合、こう書くことができます。

#ifdef __cplusplus__
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
#else
#define FOO(t,name) t name
#endif