2006-08-28

近況

前回のつづき.

なんとなく悔しいので boost MPL を使って書き直した. チュートリアルを読むのは諦め, リファレンスからのコピペで書く. boost MPL では 整数を持つのに直接 enum を使わず, かわりに 内部に enum をを持つ (メタ)整数型みたいのを定義するんだね (boost::mpl::int_). で, その型に対して計算を行う. だからメタ関数の引数は常に(整数ではなく)型になる. 確かにこっちの方が一貫性はあるかも. クドいけど...

#include <boost/mpl/int.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/times.hpp>
#include <boost/mpl/arithmetic.hpp>
#include <boost/mpl/next_prior.hpp>
#include <boost/mpl/shift_left.hpp>
#include <boost/mpl/bitand.hpp>
#include <boost/mpl/bitwise.hpp>
#include <iostream>

template<
  typename N,
  typename M = boost::mpl::int_<sizeof(int)*8-1>
  >
struct lg_t {
  typedef typename boost::mpl::int_<0> zero;
  typedef typename boost::mpl::int_<1> one;
  typedef typename boost::mpl::shift_left<one, M>::type hibit_one;
  typedef typename boost::mpl::bitand_<N, hibit_one>::type hibit;
  typedef typename boost::mpl::prior<hibit>::type prior_hibit;
  typedef typename boost::mpl::bitand_<N, prior_hibit> lobit;
  typedef typename boost::mpl::if_<lobit, one, zero>::type odd;
  typedef typename boost::mpl::plus<M, odd>::type result;
  typedef typename boost::mpl::prior<M>::type prior_m;
  typedef typename lg_t< N, prior_m >::type next;
  typedef typename boost::mpl::if_<hibit, result, next>::type type;
};

template<
  typename N
  >
struct lg_t< N, boost::mpl::int_<0> > {
  typedef typename boost::mpl::int_<0> type;
};

template<int N>
struct lg {
  enum { value = lg_t< boost::mpl::int_<N> >::type::value };
};

template<
  typename N,
  typename M
  >
struct pow_t {
  typedef typename boost::mpl::prior<M>::type rest;
  typedef typename pow_t<N, rest>::type next;
  typedef typename boost::mpl::times<N, next>::type times;
  typedef typename boost::mpl::if_<rest, times, N>::type type;
};

template<
  typename N
  >
struct pow_t<N, boost::mpl::int_<0> > {
  typedef typename boost::mpl::int_<1> type;
};

template<int N, int M>
struct pow {
  enum { value = pow_t< boost::mpl::int_<N>,
	 boost::mpl::int_<M> >::type::value };
};

int main() {
  std::cout << lg<100>::value << std::endl;
  std::cout << pow<2, 6>::value << std::endl;
  return 0;
}

長くなってしまった.

スクラッチで書く場合と比べていまいち便利さを実感しきれないなあ. 再利用できるのはいいけど, コードがくどくなるのが辛い. boost::mpl という名前空間接頭子が邪魔なのはさておき, typedef より enum を使う方が 文法が普通の言語に近くて読みやすかった. まあそんなのは慣れの問題か. 簡潔さより一貫性が重要なくらいメタ大規模なものを気合を入れて書きたい人なら, MPL を活用できるかもしれない. boost::mpl::vector などコレクションみたいのもあるようだし. (MPL でコレクションってなんだよ...)

エラーメッセージは案外読みやすい. boost::bind を使った時ほど突き放されない. メッセージの量は多いけれど, ほとんどスタックトレースみたいなかんじ. 途中はとばして最初の行だけ読めばいい. 拍子抜けするくらい.

実際に書いてみるとちょっと便利だね. メタプログラミング. 完全にマニアのおもちゃだと思っていたけれど, こういう計算をしたいことはたしかにある. 私にはまだこの路線を突き進む覚悟ができていないから, まずは指数を求めるくらいにしておこうと思いました.

まとめ: