Boost.ConstrainedValue で小数を扱う

できたよー。
以前、Boost.Ratio でつくったこれを使いました。
とりあえず、bounded だけですが、Boost.ConstrainedValue を変更することなく小数が扱えると思います。

[ソース]

#define BOOST_RATIO_EXTENSIONS
#include <boost/ratio/ratio.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/less_equal.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/divides.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/minus.hpp>

namespace detail{

namespace mpl = boost::mpl;

template<typename base, typename exponent>
struct pow : 
    mpl::if_<
        mpl::less_equal<exponent, mpl::int_<0> >,
        mpl::int_<1>,
        mpl::multiplies<pow<base, mpl::minus<exponent, mpl::int_<1> > >, base>
    >::type
{};

template<std::size_t base, std::size_t exponent>
struct pow_c : pow<
    mpl::integral_c<std::size_t, base>,
    mpl::integral_c<std::size_t, exponent>
>{};

template<typename T>
struct keta_impl :
    mpl::if_<
        mpl::less_equal<T, mpl::int_<0> >,
        mpl::int_<0>,
        mpl::plus<keta_impl<mpl::divides<T, mpl::int_<10> > >, mpl::int_<1> >
    >::type
{};

}  // namespace detai

template<typename T>
struct keta : detail::keta_impl<T>{};

namespace detail{

template<std::size_t N, std::size_t M,
    typename keta = detail::pow<mpl::int_<10>, keta<mpl::integral_c<std::size_t, M> > > >
struct float_impl : 
    boost::ratio<
        N * keta::value + M,
        keta::value
    >
{};

}  // namespace detail

template<std::size_t N, std::size_t M>
struct float_ : detail::float_impl<N, M>{
    typedef detail::float_impl<N, M> base_type;
    operator float() const{
        return float(base_type::num) / base_type::den;
    }
};


#include <boost/constrained_value.hpp>
#include <iostream>


int
main() try{
    using boost::constrained_value::bounded;
    bounded<float, float_<0,0>, float_<1,5> >::type value(0.0f);
    
    for(int i = 0 ; i < 20 ; ++i){
        std::cout << value << std::endl;
        value = value + 0.1f;
    }
    
    return 0;
}
catch(std::exception& exp){
    std::cout << exp.what() << std::endl;
}

[出力]

0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1
1.1
1.2
1.3
1.4
Attempt to give constrained object a value that is not constraint-conforming.

多分、他の奴にも対応出来そう。
あ、C++03 でも動きます。
Boost.ConstrainedValue は思ったよりも応用が出来そうなので、ちょっと欲しくなってきました。

[boost]

  • ver 1.48.0