boost::randomの罠

boostの乱数ライブラリであるboost::randomは、Mersenne Twister法をはじめとする複数の乱数発生器と、ベルヌーイ分布や正規分布などの複数の乱数分布があり、それらを組み合わせて使うことが出来るスグレモノ。
だけど、プログラム中で複数の乱数分布を使おうとしてちょっと困ったことになった。
このように、複数の乱数分布を使う場合でも、乱数発生器は同じ物を使いまわしたい場合が多い。(特に乱数種を一律に変更したいような場合など)

mt19937  engine;  // Mersenne Twister法の乱数発生器

// 0から9までの整数の一様乱数
variate_generator<mt19937, uniform_smallint<> >  gen_int(engine, uniform_smallint<>(0, 9));
// 0.0から1.0までの一様乱数
variate_generator<mt19937, uniform_real<> >  gen_real(engine, uniform_real<>(0,1));

// 乱数種を現在時刻で設定
engine.seed( ::time(0) );   // gen_intとgen_realには反映されない!

どうやらvariate_generatorは内部に乱数発生器オブジェクトのコピーを保有しているため、元の発生器をどう変更しようと反映されないという事態になってしまうようだった。
とりあえず内部に乱数発生器へのポインタを隠し持つラッパクラスを作って対処。

// boost::randomの複数の乱数分布で同じ乱数発生器を共有するためのラッパ
template <typename T> class shared_engine {
public:
  typedef T::result_type result_type;

  shared_engine(T* _engine) : engine(_engine) { }
  result_type operator()() { return (*engine)(); }

  result_type max() const { return engine->max(); }
  result_type min() const { return engine->min(); }
private:
  T*	engine;
};