角度のstrong typedef

角度のstrong typedefは今まで、tagged_realのサンプルコードとして提供していましたが、たまに使うのでライブラリ化しました。

例:

#include <iostream>
#include <shand/angle.hpp>

int main()
{
    shand::degree_f deg(45.0f);
    shand::radian_f rad = shand::angle_cast<shand::radian_f>(deg);

    std::cout << rad.get() << std::endl;

//  shand::sin(deg); // compilation error
    shand::radian_f sin_result = shand::sin(rad);
    std::cout << sin_result.get() << std::endl;
}

出力:

0.785398
0.707107

角度の単位を変換するには、angle_cast()関数テンプレートを使用します。Chronoライブラリではミリ秒や秒といった単位間の変換を型昇格として表現していますが、ディグリーとラジアンの間には昇格の関係はないと判断し、関数を通して変換することにしました。

ディグリー(度数法)とラジアン(弧度法)の角度型は、以下のように定義しています:

namespace shand {

struct degree_tag {};
struct radian_tag {};

template <class FloatingPoint>
using degree_t = shand::tagged_real<FloatingPoint, degree_tag>;
using degree_f = degree_t<float>;
using degree_d = degree_t<double>;
using degree_ld = degree_t<long double>;

template <class FloatingPoint>
using radian_t = shand::tagged_real<FloatingPoint, radian_tag>;
using radian_f = radian_t<float>;
using radian_d = radian_t<double>;
using radian_ld = radian_t<long double>;

}

degree_tradian_tが、浮動小数点数型をパラメータにとる、tagged_realエイリアステンプレートで、_f_d_ldが付いているものが、浮動小数点数型を設定済みのエイリアスになります。

その他、<cmath>ヘッダで定義されている、いくつかの数学関数で、ラジアンを受け取ったり返したりする必要のあるものは、ラップして強い型付けにしています。

namespace shand {

template <class FloatingPoint>
radian_t<FloatingPoint> sin(const radian_t<FloatingPoint>& x)
{
    return radian_t<FloatingPoint>(std::sin(x.get()));
}

...

template <class FloatingPoint>
radian_t<FloatingPoint> atan2(const FloatingPoint& y,
                              const FloatingPoint& x)
{
    return radian_t<FloatingPoint>(std::atan2(y, x));
}

}