読者です 読者をやめる 読者になる 読者になる

浮動小数点数と整数のstrong typedef

C++

整数と浮動小数点数のstrong typedefは頻繁にほしくなるので、それ用のクラスを作りました。
Effective C++読書会での発表(「Template <Programming> - テンプレートとは何か」)にも含まれていたやつです。


浮動小数点数用のtagged_realクラステンプレートと、整数用のtagged_intクラステンプレートがあり、それらには第1テンプレート引数として浮動小数点数/整数の型、第2テンプレート引数には用途に応じたタグを指定します。
テンプレートパラメータの異なるクラステンプレートは別な型と見なされるので、別な用途間の暗黙の型変換を自動的に禁止するためにタグを使用しています。


以下は、tagged_realの例として、角度の2つの表現、ディグリとラジアンそれぞれに対して型付けを行っています。get()メンバ関数を使用すれば、生の値が参照できます。

// tagged_real example
#include <boost/math/constants/constants.hpp>
#include <shand/strong_typedef/tagged_real.hpp>
#include <shand/strong_typedef/tagged_real_io.hpp>

struct degree_tag {};
struct radian_tag {};

template <class T>
using degree = shand::tagged_real<T, degree_tag>;

template <class T>
using radian = shand::tagged_real<T, radian_tag>;

template <class T>
radian<T> degree_to_radian(const degree<T>& x)
{
    return radian<T>(x.get() * boost::math::constants::pi<T>() / static_cast<T>(180.0));
}

template <class T>
degree<T> radian_to_degree(const radian<T>& x)
{
    return degree<T>(x.get() * static_cast<T>(180.0) / boost::math::constants::pi<T>());
}

int main ()
{
    // 異なる型(タグ)間での暗黙変換はできない
    {
        degree<float> deg = 90.0f;
//      radian<float> rad = deg; // コンパイルエラー!型が違う
    }

    // degreeからradianへの変換
    {
        degree<float> deg = 90.0f;
        radian<float> rad = degree_to_radian(deg);
        std::cout << rad << std::endl;
    }

    // radianからdegreeへの変換
    {
        radian<float> rad = 0.5 * boost::math::constants::pi<float>();
        degree<float> deg = radian_to_degree(rad);
        std::cout << deg << std::endl;
    }
}
1.5708
90


tagged_intも使い方は基本的に同じです。
何らかのカウンターと、エポックからの経過時間という用途の異なる2つの整数型に対してそれぞれ型付けしています。

// tagged_int example
#include <ctime>
#include <shand/strong_typedef/tagged_int.hpp>
#include <shand/strong_typedef/tagged_int_io.hpp>

struct count_tag {};
struct seconds_tag {};

int main()
{
    shand::tagged_int<std::size_t, count_tag> count = 0;
    shand::tagged_int<std::time_t, seconds_tag> seconds = std::time(0);

    // 異なる型(タグ)間での暗黙変換はできない
//  count = seconds; // コンパイルエラー!型が違う

    std::cout << count << std::endl;
    std::cout << seconds << std::endl;
}
0
1353483810

tagged_real.hpp
tagged_int.hpp

  • テスト

test_tagged_real.cpp
test_tagged_int.cpp