せっかくいい機会なので、Boost.Preprocessorのその他のData Typeも紹介してみる。前回の例では、enumのメンバは25個までしか使えない。それはarrayやtupleの実装が25個までだからだ。しかし現実的には、enumのサイズは、32bitや64bitであったりする。25個しか使えないというのはすこし問題がある。
まず、sequenceを使ってみよう。これは現在、256個までの要素が使える。これを使って先ほどのコードを書き直すと、次のようになる。
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#define HITO_PP_ENUM_MEMBER( z, n, data ) \
BOOST_PP_SEQ_ELEM(n, data) = 1 << n
#define HITO_PP_SHIFT_ENUM( name, array ) \
enum name { \
BOOST_PP_ENUM( BOOST_PP_SEQ_SIZE( array ), HITO_PP_ENUM_MEMBER, array ) \
}
#define HITO_PP_SEQ_ENUM_IDENTIFIERS \
(ONE)(TWO)(THREE)(FOUR)(FIVE)(SIX)(SEVEN)(EIGHT)(NINE)(TEN) \
(ELEVEN)(THIRTEEN)(FOURTEEN)(FIFTEEN)(SIXTEEN)(SEVENTEEN)(EIGHTEEN)(NINETEEN)(TWENTY) \
(TWENTYONE)(TWENTYTWO)(TWENTYTHREE)(TWENTYFOUR)(TWENTYFIVE)(TWENTYSIX)(TWENTYSEVEN)(TWENTYEIGHT)(TWENTYNINE)(THIRTY)
HITO_PP_SHIFT_ENUM( foo, HITO_PP_SEQ_ENUM_IDENTIFIERS ) ;
#undef HITO_PP_SEQ_ENUM_IDENTIFIERS
これは256個までいけるのだが、ひとつひとつ括弧が必要なのが、ちょっと格好悪い。sequenceを使う利点として、その数を明示する必要がないことがあるが、しかしこの括弧の読みにくさを見れば、そんな利点はどうでもよくなってしまう。
さて、listだが、これは次回に回そう。とても面倒だ。
と思ったけれど、どうしてもこの問題の場合、数字が絡むので、256個以上は難しそうだ。とりあえず、sequenceからlistを生成するメタプログラミングでお茶を濁しておこう。
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/fold_right.hpp>
#define HITO_PP_SEQ_ENUM_IDENTIFIERS \
(ONE)(TWO)(THREE)(FOUR)(FIVE)(SIX)(SEVEN)(EIGHT)(NINE)(TEN) \
(ELEVEN)(THIRTEEN)(FOURTEEN)(FIFTEEN)(SIXTEEN)(SEVENTEEN)(EIGHTEEN)(NINETEEN)(TWENTY) \
(TWENTYONE)(TWENTYTWO)(TWENTYTHREE)(TWENTYFOUR)(TWENTYFIVE)(TWENTYSIX)(TWENTYSEVEN)(TWENTYEIGHT)(TWENTYNINE)(THIRTY)
#define op(s, state, elem) (elem, state)
BOOST_PP_SEQ_FOLD_RIGHT(op, BOOST_PP_NIL, HITO_PP_SEQ_ENUM_IDENTIFIERS)
#undef op
このメタコードは、プリプロセスの結果、
(ONE , (TWO , (THREE , (FOUR , (FIVE , (SIX , (SEVEN , (EIGHT , (NINE , (TEN , (ELEVEN , (THIRTEEN , (FOURTEEN , (FIFTEEN , (SIXTEEN , (SEVENTEEN , (EIGHTEEN , (NINETEEN , (TWENTY , (TWENTYONE , (TWENTYTWO , (TWENTYTHREE , (TWENTYFOUR , (TWENTYFIVE , (TWENTYSIX , (TWENTYSEVEN , (TWENTYEIGHT , (TWENTYNINE , (THIRTY , BOOST_PP_NIL)))))))))))))))))))))))))))))
となる。これがlistである。
マクロで大量に生成するなら外部のスクリプト処理系でコード生成するようにした方がいいかなと思います。
ReplyDeleteこれなら要素数の制限もありませんし、より柔軟にかつわかりやすく書けますからね。
インテリセンスとかは確実に死にますけど…
ごく単純なものならCのマクロでも十分なんですけど、
反復や複雑な分岐を含んだものを無理にCの範囲だけでやる必要性ってあるんでしょうかね?
プログラムのビルドには、コードを生成するのには、必要なツールをすべて含めなければなりません。だからもしコードの生成にPythonを用いたら、ビルドにはPythonの実行環境が必須になりますし、自作のプログラムを用いたら、そのプログラムが必須になってしまいます。
ReplyDeleteプリプロセッサを使えば、必要なのはコンパイラだけですみます。それに、大抵の場合、生成したい機械的なパターンのコードというのは、数十から数百ぐらいですからね。プリプロセッサで十分用が足ります。
ただ、メタプログラミングを話せない人には暗号のようなコードになるのが欠点ですが。