boost::mpl

トップページ > メタプログラミング >

abstract

必要なヘッダ
<boost/mpl/list.hpp> 型リスト,
<boost/mpl/if.hpp> 条件分岐,
<boost/mpl/for_each.hpp> for_eachアルゴリズム,
<boost/mpl/integral_c.hpp> 整数定数を表す型,
<boost/mpl/*.hpp> 他必要に応じて大量に,
出来ること
Generic Template MetaProgramming
リファレンス
en / jp

sample

#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++等古めのコンパイラでは使えないようですが…。

etc

と、長いサンプルで失礼しました。

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 という本がオススメです。未読で興味を持った方は、 是非ご一読を。

see also

shinichiro.hさんによる、固定小数点数ライブラリやdumperのMPLでの実装例 兼 チュートリアル。

presented by k.inaba (kiki .a.t. kmonos.net) under CC0