FOR_EACH_なんとか マクロ

GCCのコード読んだときに、コードに、DEF_XX(TAG, "name") みたいなテーブルを作ってそれを読む箇所でDEF_XX マクロを定義して、Cのプリプロセッサだけでコンパイル時テーブルを作るみたいなテクニック
(https://github.com/gcc-mirror/gcc/blob/master/gcc/builtin-attrs.def とか)
を見て感動して、たまに使ってるのだけど、これは、DEF_XX という名前が名前空間で一個しか使えないという問題があって、駆使するとundefだらけで見辛いコードになりがち。



これを改善するために、最近は FOR_EACH マクロ手法(と心の中で呼んでいる)を使っている。

(例えば、 https://github.com/tanakamura/waifu2x-converter-cpp/blob/b798e36dc92d54c4794cde38ad9d1e7cf4c13002/src/CUDAlib.h#L96 このへんで使っている)

上の DEF_XX 手法だと、テーブルを

DEFINE_ENTRY(ENTRY_1, "entry 1", ATTR_FOO | ATTR_BAR)
DEFINE_ENTRY(ENTRY_2, "entry 2", ATTR_FOO | ATTR_BAR)
DEFINE_ENTRY(ENTRY_3, "entry 3", ATTR_FOO | ATTR_BAR)

と、書いていたのを、

#define FOR_EACH_ENTRY(F) \
 F(ENTRY_1, "entry 1", ATTR_FOO | ATTR_BAR) \
 F(ENTRY_2, "entry 2", ATTR_FOO | ATTR_BAR) \
 F(ENTRY_3, "entry 3", ATTR_FOO | ATTR_BAR)

というように書きかえる。

そして、使う箇所は、DEF_XX手法だと、

const char *name_table[] = {
#define DEFINE_ENTRY(sym, str, attr) str,
#include "def_xx.def"
#undef DEFIN_ENTRY
};

と、書いていたのを、

#define EXTRACT_STR_FROM_ENTRY(sym, str, attr) str,

const char *name_table[] = {
FOR_EACH_ENTRY(EXTRACT_STR_FROM_ENTRY)
};

というようにする。


テーブルエントリを定義するマクロ名が任意に付けられるので、undefが必要無くなるし、意味のある名前を付けられるようになる。