Re[15]: В поисках семантической корректности
От: CrystaX Россия https://crystax.me/
Дата: 23.05.05 12:01
Оценка:
Здравствуйте, CrystaX, Вы писали:

Next iteration:

#include <iostream>

#include <boost/mpl/vector.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/size.hpp>

using boost::mpl::vector;
using boost::mpl::int_;
using boost::mpl::at;
using boost::mpl::size;

//               mass    length   time
//                 |        |       |
//                 v        v       v
typedef vector<int_<1>, int_<0>, int_<0> > mass_tag;
typedef vector<int_<0>, int_<1>, int_<0> > length_tag;
typedef vector<int_<0>, int_<0>, int_<1> > time_tag;

typedef vector<int_<0>, int_<1>, int_<-1> > velocity_tag;
typedef vector<int_<1>, int_<2>, int_<-2> > energy_tag;

template <bool Condition, typename T1, typename T2> struct if_else;
template <typename T1, typename T2> struct if_else<true, T1, T2> {typedef T1 type;};
template <typename T1, typename T2> struct if_else<false, T1, T2> {typedef T2 type;};

template <int Value, unsigned Power>
struct meta_power
{
    static int const value = meta_power<Value, Power - 1>::value * Value;
};

template <int Value>
struct meta_power<Value, 0>
{
    static int const value = 1;
};

template <typename Fraction, int Power>
struct fraction_power
{
    static int const nominator = if_else<Power < 0, meta_power<Fraction::denominator, -Power>,
        meta_power<Fraction::nominator, Power> >::type::value;
    static int const denominator = if_else<Power < 0, meta_power<Fraction::nominator, -Power>,
        meta_power<Fraction::denominator, Power> >::type::value;
};


struct SystemInternational {};
struct SystemSGS {};

template <typename Tag, typename System1, typename System2>
struct unit_traits
{
private:
    typedef unit_traits<mass_tag, System1, System2> mass_traits;
    typedef unit_traits<length_tag, System1, System2> length_traits;
    typedef unit_traits<time_tag, System1, System2> time_traits;

    static int const p1 = at<Tag, int_<0> >::type::value;
    static int const p2 = at<Tag, int_<1> >::type::value;
    static int const p3 = at<Tag, int_<2> >::type::value;

public:
    static int const nominator =
        fraction_power<mass_traits, p1>::nominator *
        fraction_power<length_traits, p2>::nominator *
        fraction_power<time_traits, p3>::nominator;
    static int const denominator = 
        fraction_power<mass_traits, p1>::denominator *
        fraction_power<length_traits, p2>::denominator *
        fraction_power<time_traits, p3>::denominator;
};

template <>
struct unit_traits<mass_tag, SystemInternational, SystemSGS>
{
    // kg to g -> 1/1000
    static int const nominator = 1;
    static int const denominator = 1000;
};

template <>
struct unit_traits<mass_tag, SystemSGS, SystemInternational>
{
    // g to kg -> 1000/1
    static int const nominator = 1000;
    static int const denominator = 1;
};

template <>
struct unit_traits<length_tag, SystemInternational, SystemSGS>
{
    // m to sm
    static int const nominator = 1;
    static int const denominator = 1000;
};

template <>
struct unit_traits<length_tag, SystemSGS, SystemInternational>
{
    // sm to m
    static int const nominator = 1000;
    static int const denominator = 1;
};

template <>
struct unit_traits<time_tag, SystemInternational, SystemSGS>
{
    static int const nominator = 1;
    static int const denominator = 1;
};

template <>
struct unit_traits<time_tag, SystemSGS, SystemInternational>
{
    static int const nominator = 1;
    static int const denominator = 1;
};


template <typename T, typename System, typename Tag>
class unit
{
public:
    explicit unit(T const &t = T()) :value(t) {}
    unit(unit const &u) :value(u.value) {}

    template <typename OtherSystem>
    unit(unit<T, OtherSystem, Tag> const &u)
    :value(static_cast<T>(u) * unit_traits<Tag, System, OtherSystem>::nominator /
        unit_traits<Tag, System, OtherSystem>::denominator)
    {}

    operator T () const {return value;}
    operator T & () {return value;}

private:
    T value;
};

typedef unit<double, SystemSGS, mass_tag> mass_sgs;
typedef unit<double, SystemInternational, mass_tag> mass_si;

typedef unit<double, SystemSGS, length_tag> lenght_sgs;
typedef unit<double, SystemInternational, length_tag> lenght_si;

typedef unit<double, SystemSGS, time_tag> time_sgs;
typedef unit<double, SystemInternational, time_tag> time_si;

typedef unit<double, SystemSGS, velocity_tag> velocity_sgs;
typedef unit<double, SystemInternational, velocity_tag> velocity_si;

typedef unit<double, SystemSGS, energy_tag> energy_sgs;
typedef unit<double, SystemInternational, energy_tag> energy_si;


int main()
{
    // Test
    mass_sgs m1(1);
    mass_si m2(m1);

    std::cout << "Mass in SI: " << m2 << ", in SGS: " << m1 << std::endl;

    velocity_sgs v1(10);
    velocity_si v2(v1);

    std::cout << "Velocity in SI: " << v2 << ", in SGS:" << v1 << std::endl;

    energy_si e1(0.0001);
    energy_sgs e2(e1);

    std::cout << "Energy in SI: " << e1 << ", in SGS: " << e2 << std::endl;

    return 0;
}


Здесь уже надо указать только коэффициенты преобразования для основных типов (масса, длина, время). Все остальное будет выведено автоматически.

Что еще можно было бы улучшить? На данный момент есть привязка к количеству основных типов и их местоположению. При изменении базовых тагов придется переписывать generic unit_traits. Можно подумать насчет перебора типов автоматически... В общем, подумаю еще.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.