#include <boost/mpl/list.hpp>
#include <boost/mpl/iter_fold.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/type.hpp>
namespace mpl = boost::mpl;
using mpl::_1;
using mpl::_2;
// mpl::list<A,B,C,D,...> を与えると、
// A* create<A>();
// B* create<B>();
// C* create<C>();
// D* create<C>();
// ...
// が定義されたクラスとなるようなテンプレートGeneratorを作成。
namespace detail {
// クラス階層のルート
struct Root { void create_impl(); };
// 上位のクラス階層と、型を指すiteratorを受け取って、
// 新しいクラス階層を返すメタ関数
template<typename Base, typename ElemIte>
struct Node : Base
{
// iteratorの参照外し。つまり、Elem = *ElemIte;
typedef typename mpl::deref<ElemIte>::type Elem;
using Base::create_impl;
// ここで対応するメンバ関数を実装
Elem* create_impl( boost::type<Elem> ) { return new Elem; }
};
}
// mpl::iter_fold アルゴリズムを実行
template<typename TList>
class Generator
: mpl::iter_fold< TList, detail::Root, detail::Node<_1,_2> >::type
{
public:
template<typename T>
T* create() { return this->create_impl( boost::type<T>() ); }
};
// 使用例
#include <string>
#include <vector>
using namespace std;
int main()
{
// Generatorに型リストを渡して実体化
Generator< mpl::list<string,vector<int>,char> > g;
string* ps = g.create< string >();
vector<int>* pv = g.create< vector<int> >();
char* pc = g.create< char >();
return 0;
}
mpl::iter_fold は、STLのaccumulate とよく似たアルゴリズムです。 accumulate はだいたい、(実際はコンテナでなくてiterator2つを取ることを除けば) 次のようなアルゴリズムです。
accumulate( コンテナ v, 初期値 i, 関数 f )
{
i1 = f( i, v[0] )
i2 = f( i1, v[1] )
...
in = f( im, v[n] )
return in;
}
i が 0 で f が足し算だったら、((0+v[0])+v[1])+...+v[n] が結果になるわけです。 これに対してmpl::iter_fold は、おおざっぱに言うと(実際はもう一段複雑、 かつ逆順ですが)、
iter_fold< 型リスト v, 初期型 i, 型関数 f >
{
typedef f< i, v[0] >::type i1;
typedef f< i1, v[1] >::type i2;
...
typedef f< im, v[n] >::type in;
typedef in type;
}
という"アルゴリズム"です。上の例では i が Root で f が Node だったので、 結果は、
Node<Node<Node<Root, string>, vector<int> >, char >
という型に出来上がります。
「Nodeの定義の中にtypeなんてないじゃないか?!」という疑問はあるかと思いますが、 それは _1 と _2 によるMagicです。(^^) boost::lambda をご想像下さい。 このlambda機能は残念ながらVC++等古めのコンパイラでは使えないようですが…。
と、長いサンプルで失礼しました。
mplとはその名もMetaProgramming Libraryで、「プログラムを生成するプログラム」 のためのライブラリです。この手のメタプログラムには、例えば構文解析器生成の YACC などがありますが、これはCとは別の言語を使って書いて、 Cのプログラムを生成する、というものでした。
C++では、templateを用いてC++上で、C++のメタプログラミングを実現できます。 template は、「型や整数を受け取って型や整数を返すメタ関数」です。 「typedef は型変数の定義」で「templateの特殊化は条件分岐」と言った調子。 mplはこのtemplate-metaの世界における、STLのように汎用的な "データ構造"と"アルゴリズム"の実装となっています。
更に驚くべき事に、これだけtemplateを使い回していながら、 VC++やBcc5.5xなどの難のあるコンパイラでもmplのほとんどが使用可能。
この手のものを使うとどんな汎用的なものが作れるのか?については、具体例として Modern C++ Design という本がオススメです。未読で興味を持った方は、 是非ご一読を。