私は、C++ の列挙型を簡単にするための小さなライブラリを作成しています。構文は次のようなものです。
ENUM_START(MyEnum)
ENUM_VAL(Val1)
ENUM_VAL(Val2)
...
ENUM_END
このマクロは、たとえば次のアクセスを許可するクラス MyEnum を作成します。
MyEnum bla=MyEnum::Val1;
for(MyEnum::iterator iter=MyEnum::begin();iter!=MyEnum::end();++iter)
cout << iter->toString();
追加のデータ (文字列など) を列挙値に格納するなど、さらにいくつかの機能があります。
マクロは完成して機能しますが、上記のように定義するのは簡単ではありません。このためには、後で呼び出すことができる ENUM_VAL マクロを使用して初期化関数のリストを作成する方法が必要です。次の boost::mpl アプローチのようなもの:
typedef mpl::vector<> list__COUNTER__;
#define ENUM_VAL(Name) \
... \
struct Init##Name{void init() {initialization code}}; \
typedef mpl::push_back< \
list##(__COUNTER-1), \
Init##Name \
>::type list##__COUNTER__; \
このように list##(__COUNTER__-1) は最後に Init##Name 型を含み、最後に mpl foreach を使用してすべての格納された型で init() を呼び出すことができます。
今の問題はネーミングです。マクロのインスタンス化ごとに __COUNTER__ を 2 回使用する必要があり、これによりカウンターが 2 回インクリメントされます。さっき検索して知った
- C プリプロセッサは、変数に名前を付けるときに (__COUNTER__-1) を計算しません
- インクリメントせずに __COUNTER__ を読み取る方法はありません。
そのため、後で呼び出すことができる関数のリストを収集する別の方法が必要です。