前に作ったPP_IS_EMPTYの問題点

以前、PP_TUPLE_SIZEを作るために作ったPP_IS_EMPTYがどうなっていたのか思いだしたら、少しばかり問題がありました。


#define FOO(a, b, c)
PP_IS_EMPTY(e FOO)
eをカンマで区切られていないトークン列として、上記のようなトークン列を引数とすると、置換に失敗してエラーとなってしまいます。詳しく書くと面倒なのでソースを見て分かってください。
これを修正するには、全く別のアプローチが必要になりそうですが、これよりいい方法は思いつきませんでした。
それともう一つ、Wave driverで遊んでいたmelponさんから、可変長引数マクロの使い方が間違っているのではないか、という報告を受けました。
#define FOO(a, ...) という定義の引数付きマクロに対して、 FOO(e) と書くのはどうやら規格的にはwell-formedではないようです。VCやgccは、これを私の意図した通りに展開してしまいますが。
こちらではC++0xのdraftから引用してみます。
n3035 Working Draft, Standard for Programming Language C++ §16.3.1.12

If there is a ... in the identifier-list in the macro definition, then the trailing arguments, including any separating comma preprocessing tokens, are merged to form a single item: the variable arguments. The number of arguments so combined is such that, following merger, the number of arguments is one more than the number of parameters in the macro definition (excluding the ...).

(読み間違えていなければ)前述の形式の引数付きマクロは、マクロ定義に登場するパラメータの数( ... は除く)より1つ以上多くの引数を要求します。で、これが先のコードのどこに影響するのかというと、
#define PP_IS_EMPTY_VIII(a, ...) PP_IS_EMPTY_IX((HELPER_IV_ ## a))
の展開です。PP_IS_EMPTY_VIIIには、PP_IS_EMPTYの引数を展開すると空になる場合、EMPTYというトークンが渡されるのですが、これは1つの引数なので、上記の通り、正しいマクロ置換のコードとは言えません。
これに対する修正は簡単で、PP_IS_EMPTY_Vの定義を、


#define PP_IS_EMPTY_V(a, ...) PP_IS_EMPTY_VI)((a __VA_ARGS__ (), NIL))(
のようにすれば解決します。 PP_IS_EMPTY_VIII に2引数以上渡るようにしただけです。

そもそもなんでタプルをどうのこうのってことになったのかと言うと、ふとプリプロセス時にラムダ式を書けないかと色々考えた挙句、できそうと言う結論に達した(普通に式を書けるわけではない)ので、せっかくだから少しでも見た目がかっこいいタプルで作ってやろうとして、PP_IS_EMPTYを思いだしたわけです。というわけでそのうち作るかもしれないし、作らないです。