Boost.Accumulatorsを拡張する

Boost 1.36.0 から追加された Boost.Accumulators。統計関数がいろいろあるのですが、標準偏差がないっぽいなぁということで、作ってみました。

拡張方法はドキュメントに書いてあるようなのですが読んでもよくわからなかったのでソース読みつつ適当にやってみました。

#include <cmath>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
using namespace boost::accumulators;

namespace boost { namespace accumulators {
namespace impl {

    template<typename Sample, typename VarianceFeature>
    struct rms_impl
      : accumulator_base
    {
        typedef Sample result_type;

        template<typename Args>
        rms_impl(Args const & args)
          : rms_(args[sample | Sample()])
        {
        }
        
        template<typename Args>
        void operator ()(Args const & args)
        {
            rms_ = variance(args);
        }
        
        result_type result(dont_care) const
        {
            return std::sqrt(this->rms_);
        }
    private:
        Sample rms_;
    };

} // impl

namespace tag {
    struct rms
      : depends_on<variance>
    {
        typedef accumulators::impl::rms_impl<mpl::_1, variance> impl;
    };
} // tag

namespace extract {
    extractor<tag::rms> const rms = {};
} // extract
using extract::rms;

}} // boost::accumulators

で、できたっぽい。

/// 使ってみる

#include <iostream>
using namespace std;

int main()
{
    accumulator_set<double, features<tag::rms>> acc;
    acc(1);
    acc(5);
    acc(10);

    cout << extract::rms(acc) << endl;
}

一度作ってしまえばboost::accumulators名前空間の部分を適当にコピペするだけで量産できそうではあります。

tag::rms の第二テンプレート引数をvarianceに決め打ちするのでなく使用する側に設定させれば、「何かした後にsqrtする」関数になるのかな。error_ofがそんな感じ?(よくわかってない)