Re[9]: В поисках семантической корректности
От: Кодт Россия  
Дата: 19.05.05 12:50
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Лечится определением констант в одном единственном заголовочном файле. Тоже конвенция, однако.


Лечится очень хреново.
Во-первых, отягощает компиляцию (изменения в этом файле вынудят перестроить весь проект).
Во-вторых, неустойчив к совмещениям.
В-третьих, усложняет деплоймент (а главное — подключение) библиотек.

Конвенция же объявления типов — локализована двумя стейтментами и может быть сведена к макросу
#define DECLARE_UNIT(name, base) struct tag_##name {}; typedef unit<base,tag_##name> name;
http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!
Re[10]: В поисках семантической корректности
От: CrystaX Россия https://www.crystax.net/
Дата: 19.05.05 13:04
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, CrystaX, Вы писали:


CX>>Лечится определением констант в одном единственном заголовочном файле. Тоже конвенция, однако.


К>Лечится очень хреново.

К>Во-первых, отягощает компиляцию (изменения в этом файле вынудят перестроить весь проект).
К>Во-вторых, неустойчив к совмещениям.
К>В-третьих, усложняет деплоймент (а главное — подключение) библиотек.

Быть может. Но лучше все же использовать не некоторые идентификаторы типов (неважно, в форме констант или типов-тэгов), а некую единообразную систему единиц.

Вот есть у нас в программе типы масса, длина и время. Определяем типы:
#include <boost/mpl/vector.hpp>
#include <boost/mpl/int.hpp>

using boost::mpl::vector;
using boost::mpl::int_;

//               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;


Вот и имеем нормальные идентификаторы типов. В данном случае мы уж точно не ошибемся, так как каждому типу соответствует не какой-то непонятный идентификатор, а размерность.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[11]: В поисках семантической корректности
От: Кодт Россия  
Дата: 19.05.05 15:22
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Быть может. Но лучше все же использовать не некоторые идентификаторы типов (неважно, в форме констант или типов-тэгов), а некую единообразную систему единиц.

<>
CX>Вот и имеем нормальные идентификаторы типов. В данном случае мы уж точно не ошибемся, так как каждому типу соответствует не какой-то непонятный идентификатор, а размерность.

Кто бы спорил. Размерности — это отдельная и очень интересная тема. Главное, над ними есть арифметика.
Правда, я не очень понимаю, как в бусте (да и в метапрограммировании С++ вообще) красиво ввести масштабирование (скажем, "длина" может быть в СИ — в метрах, в СГС — в сантиметрах, а ещё в дюймах и локтях — при этом дюймы можно складывать с локтями, пересчитывая коэффициенты).
http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!
Re[12]: В поисках семантической корректности
От: WolfHound  
Дата: 19.05.05 15:45
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Кто бы спорил. Размерности — это отдельная и очень интересная тема. Главное, над ними есть арифметика.

Однажды мне было нечего делать...
Пример использования:
#include "stdafx.h"
#define PHYSIC_TYPES_PARAMS            \
(                                    \
    (distance)                        \
    (time)                            \
    (mass)                            \
,                                    \
    ((velocity, distance/time))        \
    ((accelerate, velocity/time))    \
)                                    \
//end macro
#include "physic_type.h"
PHYSIC_TYPE_DECLARE(float)
int main()
{
    distance_pt d=0;
    time_pt t=0;
    velocity_pt v=0;
    accelerate_pt a=0;
    v=d/t;
    v=v+v;
    v=a*t;
    a=v/t;
    t=d/v;
    d=v*t;
    d=(v+a*t)*t;
    //d=v/t;//error
    //t=v/d;//error
    return 0;
}



meta.h
#pragma once
template<class T>
struct t2t
{
    typedef T type;
};

template<int P>
struct power_native_to_meta
{
    enum
    {
        value
            =P>0
            ?P*2
            :-P*2+1
    };
};
template<int P>
struct power_meta_to_native
{
    enum
    {
        value
            =P%2==0
            ?P/2
            :-(P-1)/2
    };
};
template<int P>
struct get_power_ret
{
    typedef char(&type)[power_native_to_meta<P>::value];
};

physic_type.h
#pragma once
#include "meta.h"

#define BASIC_PHYSIC_TYPES                                    BOOST_PP_TUPLE_ELEM(2, 0, PHYSIC_TYPES_PARAMS)
#define COMPLEX_PHYSIC_TYPES                                BOOST_PP_TUPLE_ELEM(2, 1, PHYSIC_TYPES_PARAMS)

#define BASIC_PHYSIC_TYPES_COUNT                            BOOST_PP_SEQ_SIZE(BASIC_PHYSIC_TYPES)

#define PHYSIC_TYPES_TEMPLATE_PARAM(z,n,d)                    int BOOST_PP_CAT(BOOST_PP_CAT(P, n), d)
#define PHYSIC_TYPES_TEMPLATE_PARAMS(d)                        BOOST_PP_ENUM(BASIC_PHYSIC_TYPES_COUNT, PHYSIC_TYPES_TEMPLATE_PARAM, d)

#define PHYSIC_TYPES_TEMPLATE_ARG(z,n,d)                    BOOST_PP_CAT(BOOST_PP_CAT(P, n), d)
#define PHYSIC_TYPES_TEMPLATE_ARGS(d)                        BOOST_PP_ENUM(BASIC_PHYSIC_TYPES_COUNT, PHYSIC_TYPES_TEMPLATE_ARG, d)

#define PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS(pred)            BOOST_PP_ENUM(BASIC_PHYSIC_TYPES_COUNT, pred, _)

#define PHYSIC_TYPES_COMPOSE_TEMPLATE_ARG_ADD(z, n, d)        BOOST_PP_CAT(BOOST_PP_CAT(P, n), _x1)+BOOST_PP_CAT(BOOST_PP_CAT(P, n), _x2)
#define PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS_ADD()            PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS(PHYSIC_TYPES_COMPOSE_TEMPLATE_ARG_ADD)

#define PHYSIC_TYPES_COMPOSE_TEMPLATE_ARG_SUB(z, n, d)        BOOST_PP_CAT(BOOST_PP_CAT(P, n), _x1)-BOOST_PP_CAT(BOOST_PP_CAT(P, n), _x2)
#define PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS_SUB()            PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS(PHYSIC_TYPES_COMPOSE_TEMPLATE_ARG_SUB)

template<class T, PHYSIC_TYPES_TEMPLATE_PARAMS(_x)>
struct physic_type
{
    template<class U>
    struct rebind
    {
        typedef physic_type<U, PHYSIC_TYPES_TEMPLATE_ARGS(_x)> type;
    };
    physic_type()
        :data()
    {}
    physic_type(T data)
        :data(data)
    {}
    physic_type(physic_type const& that)
        :data(that.data)
    {}

    physic_type& operator=(physic_type const& that)
    {
        data=that.data;
        return *this;
    }

    physic_type& operator+=(physic_type const& that)
    {
        data+=that.data;
        return *this;
    }
    physic_type& operator-=(physic_type const& that)
    {
        data-=that.data;
        return *this;
    }

    T get()const
    {
        return data;
    }
private:
    T data;
};

template<class T, PHYSIC_TYPES_TEMPLATE_PARAMS(_x)>
physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x)> operator+
    (physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x)> const& l
    ,physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x)> const& r
    )
{
    return physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x)>(l)+=r;
}

template<class T, PHYSIC_TYPES_TEMPLATE_PARAMS(_x)>
physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x)> operator-
    (physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x)> const& l
    ,physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x)> const& r
    )
{
    return physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x)>(l)-=r;
}

template<class T, PHYSIC_TYPES_TEMPLATE_PARAMS(_x1), PHYSIC_TYPES_TEMPLATE_PARAMS(_x2)>
physic_type<T, PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS_ADD()> operator*
    (physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x1)> const& l
    ,physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x2)> const& r
    )
{
    return physic_type<T, PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS_ADD()>(l.get()*r.get());
}

template<class T, PHYSIC_TYPES_TEMPLATE_PARAMS(_x1), PHYSIC_TYPES_TEMPLATE_PARAMS(_x2)>
physic_type<T, PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS_SUB()> operator/
    (physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x1)> const& l
    ,physic_type<T, PHYSIC_TYPES_TEMPLATE_ARGS(_x2)> const& r
    )
{
    return physic_type<T, PHYSIC_TYPES_COMPOSE_TEMPLATE_ARGS_SUB()>(l.get()/r.get());
}

#define PRED(r, state)                                    \
    BOOST_PP_NOT_EQUAL(                                    \
        BOOST_PP_TUPLE_ELEM(3, 0, state),                \
        BOOST_PP_TUPLE_ELEM(3, 1, state)                \
    )                                                    \
//end macro
#define OP(r, state)                                    \
    (                                                    \
        BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(3, 0, state)),    \
        BOOST_PP_TUPLE_ELEM(3, 1, state),                \
        BOOST_PP_TUPLE_ELEM(3, 2, state)                \
    )                                                    \
//end macro

#define MACRO(r, state) ,                                \
    BOOST_PP_IF                                            \
    (                                                    \
        BOOST_PP_EQUAL                                    \
            (BOOST_PP_TUPLE_ELEM(3, 0, state)            \
            ,BOOST_PP_TUPLE_ELEM(3, 2, state)            \
            )                                            \
        ,1                                                \
        ,0                                                \
    )                                                    \
//end macro

#define PHYSIC_TYPES_DETECT_SIZE(z, N, text)                                                                                    \
template<class T, BOOST_PP_ENUM_PARAMS(BASIC_PHYSIC_TYPES_COUNT, int n)>                                                            \
char(&detect_size_##N(physic_type<T, BOOST_PP_ENUM_PARAMS(BASIC_PHYSIC_TYPES_COUNT, n)>))[power_native_to_meta<n##N>::value];    \
//end macro
BOOST_PP_REPEAT(BASIC_PHYSIC_TYPES_COUNT, PHYSIC_TYPES_DETECT_SIZE, _)

#define PHYSIC_TYPES_GET_SIZE(z, N, T)                                \
    power_meta_to_native<sizeof(detect_size_##N(T))>::value            \
//end macro
#define PHYSIC_TYPES_GET_SIZES(T)                                    \
BOOST_PP_ENUM(BASIC_PHYSIC_TYPES_COUNT, PHYSIC_TYPES_GET_SIZE, T)    \
//end macro

namespace detail
{
    typedef double type;

    #define BASIC_PHYSIC_TYPE_DEFINE(r, data, i, elem)                                                                        \
        typedef physic_type<type BOOST_PP_FOR((0, BASIC_PHYSIC_TYPES_COUNT, i), PRED, OP, MACRO)> BOOST_PP_CAT(elem, _pt);    \
        static BOOST_PP_CAT(elem, _pt) elem;                                                                                \
        //end macro
    BOOST_PP_SEQ_FOR_EACH_I(BASIC_PHYSIC_TYPE_DEFINE, _, BASIC_PHYSIC_TYPES)
    #undef BASIC_PHYSIC_TYPE_DEFINE

    #define COMPLEX_PHYSIC_TYPE_DEFINE(r, data, elem)                                                                                            \
        typedef physic_type<type, PHYSIC_TYPES_GET_SIZES(BOOST_PP_TUPLE_ELEM(2, 1, elem))> BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, elem), _pt);    \
        static BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, elem), _pt) BOOST_PP_TUPLE_ELEM(2, 0, elem);                                                \
        //end macro
    BOOST_PP_SEQ_FOR_EACH(COMPLEX_PHYSIC_TYPE_DEFINE, _, COMPLEX_PHYSIC_TYPES)
    #undef COMPLEX_PHYSIC_TYPE_DEFINE
}
//===========================================================================================================================================================================
#define BASIC_PHYSIC_TYPE_DEFINE(r, T, elem)                        \
    typedef detail::BOOST_PP_CAT(elem, _pt)::rebind<T>::type    \
        BOOST_PP_CAT(elem, _pt);                                \
    //end macro
//===========================================================================================================================================================================
#define COMPLEX_PHYSIC_TYPE_DEFINE(r, T, elem)                                            \
    typedef detail::BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, elem), _pt)::rebind<T>::type    \
        BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, elem), _pt);                                \
    //end macro
//===========================================================================================================================================================================
#define PHYSIC_TYPE_DECLARE(T)                                                \
BOOST_PP_SEQ_FOR_EACH(BASIC_PHYSIC_TYPE_DEFINE, T, BASIC_PHYSIC_TYPES)        \
BOOST_PP_SEQ_FOR_EACH(COMPLEX_PHYSIC_TYPE_DEFINE, T, COMPLEX_PHYSIC_TYPES)    \
    //end macro
//===========================================================================================================================================================================
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: В поисках семантической корректности
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 19.05.05 17:39
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Здравствуйте, Кодт, Вы писали:


К>>Здравствуйте, CrystaX, Вы писали:


CX>>>>>Хочешь, я тебе подобную же ошибку придумаю и в варианте с типами?

W>>>>В том то и дело, что ее нужно придумывать. Запоминать имя проще, чем число — факт.

CX>>>Согласен. Именно поэтому я и предложил использовать именованные константы. Ты же "придумал" ошибку с числами.

CX>>>В общем, принципиальной разницы между вариантом с именованными константами и вариантом с типами-тэгами не вижу.

CX>>>>>Надо защищаться от непреднамеренных ошибок, а не от преднамеренных.


К>>Непреднамеренная:

К>>
К>>// p1.h
К>>const int ident_piastr = 1;
К>>typedef unit<double,ident_piastr> piastr;

К>>// p2.h
К>>const int ident_percent = 1;
К>>typedef unit<double,ident_percent> percent;

К>>// all.h
К>>#include "p1.h"
К>>#include "p2.h"
К>>


CX>Лечится определением констант в одном единственном заголовочном файле. Тоже конвенция, однако.


Не всегда возможно, имхо. Особенно, если файл с большинством констант является частью стороннего продукта, а тебе нужно лишь дополнить этот набор парой-тройкой своих констант.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[10]: В поисках семантической корректности
От: CrystaX Россия https://www.crystax.net/
Дата: 20.05.05 06:44
Оценка:
Здравствуйте, eao197, Вы писали:

CX>>Лечится определением констант в одном единственном заголовочном файле. Тоже конвенция, однако.


E>Не всегда возможно, имхо. Особенно, если файл с большинством констант является частью стороннего продукта, а тебе нужно лишь дополнить этот набор парой-тройкой своих констант.


Согласен, не всегда. Но проблема, на мой взгляд, несколько надуманная. На мой взгляд, нет принципиальной разницы, как именно определять уникальность типов — с помощью числовых идентификаторов или с помощью типов-тэгов. И в том, и в другом случае остается возможность ошибки, причем полностью защититься от этого нельзя, это отдается на откуп программисту — автору кода.
Практическое же решение, на мой взгляд — то, что я привел немного выше. Смотри здесь
Автор: CrystaX
Дата: 19.05.05
.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[12]: В поисках семантической корректности
От: CrystaX Россия https://www.crystax.net/
Дата: 20.05.05 07:32
Оценка: 1 (1)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, CrystaX, Вы писали:


CX>>Быть может. Но лучше все же использовать не некоторые идентификаторы типов (неважно, в форме констант или типов-тэгов), а некую единообразную систему единиц.

К><>
CX>>Вот и имеем нормальные идентификаторы типов. В данном случае мы уж точно не ошибемся, так как каждому типу соответствует не какой-то непонятный идентификатор, а размерность.

К>Кто бы спорил. Размерности — это отдельная и очень интересная тема. Главное, над ними есть арифметика.

К>Правда, я не очень понимаю, как в бусте (да и в метапрограммировании С++ вообще) красиво ввести масштабирование (скажем, "длина" может быть в СИ — в метрах, в СГС — в сантиметрах, а ещё в дюймах и локтях — при этом дюймы можно складывать с локтями, пересчитывая коэффициенты).

Ммм... Ну а в чем проблема?

#include <iostream>

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

using boost::mpl::vector;
using boost::mpl::int_;

//               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;

struct SystemInternational {};
struct SystemSGS {};

template <typename Tag, typename System1, typename System2>
struct unit_traits
{
    // Default coefficient is 1
    static int const nominator = 1;
    static int const denominator = 1;
};

// Описываем свойства основных единиц - массы, длины, времени

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 <typename System1, typename System2>
struct unit_traits<velocity_tag, System1, System2>
{
    static int const nominator = unit_traits<length_tag, System1, System2>::nominator * 
        unit_traits<time_tag, System1, System2>::denominator;
    static int const denominator = unit_traits<length_tag, System1, System2>::denominator *
        unit_traits<time_tag, System1, System2>::nominator;
};

template <typename System1, typename System2>
struct unit_traits<energy_tag, System1, System2>
{
    static int const nominator =
        unit_traits<mass_tag, System1, System2>::nominator *
        unit_traits<length_tag, System1, System2>::nominator *
        unit_traits<length_tag, System1, System2>::nominator *
        unit_traits<time_tag, System1, System2>::denominator *
        unit_traits<time_tag, System1, System2>::denominator;
    static int const denominator =
        unit_traits<mass_tag, System1, System2>::denominator *
        unit_traits<length_tag, System1, System2>::denominator *
        unit_traits<length_tag, System1, System2>::denominator *
        unit_traits<time_tag, System1, System2>::nominator *
        unit_traits<time_tag, System1, System2>::nominator;
};

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;
}
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[13]: В поисках семантической корректности
От: Кодт Россия  
Дата: 22.05.05 10:31
Оценка:
Здравствуйте, CrystaX, Вы писали:

К>>Правда, я не очень понимаю, как в бусте (да и в метапрограммировании С++ вообще) красиво ввести масштабирование (скажем, "длина" может быть в СИ — в метрах, в СГС — в сантиметрах, а ещё в дюймах и локтях — при этом дюймы можно складывать с локтями, пересчитывая коэффициенты).


CX>Ммм... Ну а в чем проблема?

<>

Да, решение с traits — симпатичное. Единственное пожелание — чтобы не писать множитель для каждого типа, а выводить их из базисных.
template<int M, int L, int T, int Q // размерность: масса,длина,время,заряд
         class S1, class S2 // тэги систем
        >
struct unit_traits
{
  static double scale()
  { static s = pow(unit_traits<1,0,0,0,S1,S2>::scale(),M)
             * pow(unit_traits<0,1,0,0,S1,S2>::scale(),L)
             * pow(unit_traits<0,0,1,0,S1,S2>::scale(),T)
             * pow(unit_traits<0,0,0,2,S2,S3>::scale(),Q);
    return s;
  }
};
// и соответствующие специализации для ортов

Кстати, для внесистемных единиц (наподобие температуры в кельвинах или мощности в лошадиных силах) придётся тоже что-то придумывать.
http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!
Re[14]: В поисках семантической корректности
От: CrystaX Россия https://www.crystax.net/
Дата: 23.05.05 07:46
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Да, решение с traits — симпатичное. Единственное пожелание — чтобы не писать множитель для каждого типа, а выводить их из базисных.

К>
К>template<int M, int L, int T, int Q // размерность: масса,длина,время,заряд
К>         class S1, class S2 // тэги систем
        >>
К>struct unit_traits
К>{
К>  static double scale()
К>  { static s = pow(unit_traits<1,0,0,0,S1,S2>::scale(),M)
К>             * pow(unit_traits<0,1,0,0,S1,S2>::scale(),L)
К>             * pow(unit_traits<0,0,1,0,S1,S2>::scale(),T)
К>             * pow(unit_traits<0,0,0,2,S2,S3>::scale(),Q);
К>    return s;
К>  }
К>};
К>// и соответствующие специализации для ортов
К>


1. У меня они как раз и выводятся из базисных. Или я неверно понял?
2. Здесь, насколько я понимаю, вычисление производится в run-time. У меня в первом варианте — в compile-time. Хотя, наверное, можно ввести метафункцию pow...

Надо подумать. Причина введения числителя и знаменателя отдельно была в том, что нельзя использовать статические константы типа double. Но конечно, если как следует подумать, наверняка можно что-нибудь соорудить...

К>Кстати, для внесистемных единиц (наподобие температуры в кельвинах или мощности в лошадиных силах) придётся тоже что-то придумывать.


Ну, в данном случае это не проблема. Вводим еще одну систему единиц (например, SystemExt) и дело в шляпе!
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[12]: В поисках семантической корректности
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 23.05.05 07:57
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Кто бы спорил. Размерности — это отдельная и очень интересная тема. Главное, над ними есть арифметика.

К>Правда, я не очень понимаю, как в бусте (да и в метапрограммировании С++ вообще) красиво ввести масштабирование (скажем, "длина" может быть в СИ — в метрах, в СГС — в сантиметрах, а ещё в дюймах и локтях — при этом дюймы можно складывать с локтями, пересчитывая коэффициенты).

В boost.date_time есть часы, секунды и тд, но это чистый runtime, AFAIK.
Re[15]: В поисках семантической корректности
От: CrystaX Россия https://www.crystax.net/
Дата: 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>>
Re[15]: В поисках семантической корректности
От: Кодт Россия  
Дата: 23.05.05 19:37
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>1. У меня они как раз и выводятся из базисных. Или я неверно понял?


Выводятся, но вручную. Тебе пришлось расписывать мультипликатор для энергии, потом для скорости, потом для мощности, потом для температуры... и тэ дэ и тэ пэ.

CX>2. Здесь, насколько я понимаю, вычисление производится в run-time. У меня в первом варианте — в compile-time. Хотя, наверное, можно ввести метафункцию pow...


Во-первых, а велик ли оверхед? С использованием кеширования (статических переменных внутри функций scale) он сойдёт на нет.
Во-вторых, рациональными числами обойтись проблематично именно для многих общепринятых величин. Система СИ меряет температуру в кельвинах, яркость в канделах, что там ещё есть хитрое? Всякие кюри и рентгены...

А с метафункцией сложности именно в том, что надо вещественные константы затащить в компиляцию шаблонов...

CX>Надо подумать. Причина введения числителя и знаменателя отдельно была в том, что нельзя использовать статические константы типа double. Но конечно, если как следует подумать, наверняка можно что-нибудь соорудить...


К>>Кстати, для внесистемных единиц (наподобие температуры в кельвинах или мощности в лошадиных силах) придётся тоже что-то придумывать.


CX>Ну, в данном случае это не проблема. Вводим еще одну систему единиц (например, SystemExt) и дело в шляпе!


Какие будут орты в системе, где мощность меряется в лошадиных силах?
лошадиная_нога * секунда * килограмм
метр * игого * килограмм
метр * секунда * лошадиная_задница
или этот коэффициент будет равномерно размазан?
http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!
Re[16]: В поисках семантической корректности
От: CrystaX Россия https://www.crystax.net/
Дата: 24.05.05 06:16
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, CrystaX, Вы писали:


CX>>1. У меня они как раз и выводятся из базисных. Или я неверно понял?


К>Выводятся, но вручную. Тебе пришлось расписывать мультипликатор для энергии, потом для скорости, потом для мощности, потом для температуры... и тэ дэ и тэ пэ.


Это уже решено здесь
Автор: CrystaX
Дата: 23.05.05


CX>>2. Здесь, насколько я понимаю, вычисление производится в run-time. У меня в первом варианте — в compile-time. Хотя, наверное, можно ввести метафункцию pow...


К>Во-первых, а велик ли оверхед? С использованием кеширования (статических переменных внутри функций scale) он сойдёт на нет.

К>Во-вторых, рациональными числами обойтись проблематично именно для многих общепринятых величин. Система СИ меряет температуру в кельвинах, яркость в канделах, что там ещё есть хитрое? Всякие кюри и рентгены...

В любом случае ты введешь некоторую рациональную дробь. Что даст тебе с достаточной степенью точности коэффициент пересчета. Вот как ты коэффициент для системы СИ в законе Кулона выведешь? Что пи, что эпсилон-0 в нем являются числами иррациональными, но мы используем достаточно приближенные к ним рациональные числа (3.1415926, 8,85e-12). Хотя, конечно, если использовать int nominator и int denominator, возможно переполнение, особенно если использовать константы типа постоянной Планка...
В общем, я еще подумаю над этим.

К>А с метафункцией сложности именно в том, что надо вещественные константы затащить в компиляцию шаблонов...


Скорее всего этот вопрос действительно будет непринципиален. Но для теоретической чистоты хотелось произвести максимум возможных вычислений в compile-time.

К>>>Кстати, для внесистемных единиц (наподобие температуры в кельвинах или мощности в лошадиных силах) придётся тоже что-то придумывать.


CX>>Ну, в данном случае это не проблема. Вводим еще одну систему единиц (например, SystemExt) и дело в шляпе!


К>Какие будут орты в системе, где мощность меряется в лошадиных силах?

К>лошадиная_нога * секунда * килограмм
К>метр * игого * килограмм
К>метр * секунда * лошадиная_задница
К>или этот коэффициент будет равномерно размазан?
К>

А здесь не надо вводить все орты. Система измерений у нас — это всего лишь тэг. Просто вводим специализацию для случая мощности и все работает! Вот пример:
struct SystemExt {};

typedef vector<int_<1>, int_<2>, int_<-3> > power_tag;

template <>
struct unit_traits<power_tag, SystemInternational, SystemExt>
{
    static int const nominator = 1471;
    static int const denominator = 2;
};

template <>
struct unit_traits<power_tag, SystemExt, SystemInternational>
{
    static int const nominator = 2;
    static int const denominator = 1471;
};

typedef unit<double, SystemExt, power_tag> power_ext;
typedef unit<double, SystemInternational, power_tag> power_si;

....
int main()
{
    power_si p1(1000);
    power_ext p2(p1);

    std::cout << "Power in SI: " << p1 << ", in Ext system: " << p2 << std::endl;

    return 0;
}


Вывод:
Power in SI: 1000, in Ext system: 1.35962


quod erat demonstrandum.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[16]: В поисках семантической корректности
От: Chez Россия  
Дата: 04.08.05 13:11
Оценка:
Здравствуйте, CrystaX, Вы писали:

Странно, что в самом бусте нету этого. Только в качестве примера.

Chez, ICQ#161095094 http://web.icq.com/whitepages/online?icq=161095094&img=1

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re[17]: В поисках семантической корректности
От: CrystaX Россия https://www.crystax.net/
Дата: 04.08.05 13:14
Оценка:
Здравствуйте, Chez, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


C>Странно, что в самом бусте нету этого. Только в качестве примера.


Ну что же делать — не все есть в бусте. Этот код (улучшенный и дополненный) я активно использую. Если есть желание, могу поделиться.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[18]: В поисках семантической корректности
От: Chez Россия  
Дата: 04.08.05 14:03
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Здравствуйте, Chez, Вы писали:


C>>Здравствуйте, CrystaX, Вы писали:


C>>Странно, что в самом бусте нету этого. Только в качестве примера.


CX>Ну что же делать — не все есть в бусте. Этот код (улучшенный и дополненный) я активно использую. Если есть желание, могу поделиться.

есть желание, пожалуйста
я думаю даже есть смысл его в исходники положить.
а если вы не согласны, то на chezu<at>pisem.net

Chez, ICQ#161095094 http://web.icq.com/whitepages/online?icq=161095094&img=1

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re[19]: В поисках семантической корректности
От: CrystaX Россия https://www.crystax.net/
Дата: 04.08.05 14:13
Оценка:
Здравствуйте, Chez, Вы писали:

CX>>Ну что же делать — не все есть в бусте. Этот код (улучшенный и дополненный) я активно использую. Если есть желание, могу поделиться.

C>есть желание, пожалуйста
C>я думаю даже есть смысл его в исходники положить.
C>а если вы не согласны, то на chezu<at>pisem.net

Ок, положу в исходники. Как до дому дойду, так сразу и положу.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[2]: В поисках семантической корректности
От: Аноним  
Дата: 04.08.05 15:07
Оценка:
Здравствуйте, SeRya, Вы писали:

SR>Идея учета размерности и других свойст велечин (здесь — диапазон), конечно, интересна, но не стеляешь ли ты из пушки по воробьям?


Если речь идёт о программе, которыую пишет один программист и забывает о ней, то, конечно, да. А если о проекте, который пишет несколько человек несколько лет, причём большая часть из них — студетны то — нет.

SR>Судя по тому, что у тебя Discount — это класс, а discount — имеет тип double, ты не до конца понимаешь то, что хочешь или по крайней мере путаешься в терминологии.


А что такого?

SR>Про комментарий я вообще молчу. Ощущение такое, что он написан для тех, кто не знает синтаксиса конструктора и ссылочного типа


У людей, которых заставляют комментировать по стандарту, — это больная тема Хотя это вроде на стандарт не похоже...

Меня прикалывает такие комметарии:

/** Массив */
class Vector
{

...
/** Получить размер массива
* @return Размер массива
*/
int getSize();

...
};


SR>Если у тебя числа хранятся как попало и где попало преобразуются в Discount, то ошибиться легко. Но если информация о представлении Discount инкапсулирована, то проблем скорее всего не возникнет.


Ну так он о том говорит, что бы её инкапсулировать, а не передавать через double.
Ну у него-то она может быть и инкапсулирована, а у студента, который будет через пять лет это дописывать не будет инкапсулирована

В общем я — за!


з.ы. про студентов — это я собирательно, просьба не обижаться, сам — студент
Re[2]: В поисках семантической корректности
От: remark Россия http://www.1024cores.net/
Дата: 04.08.05 15:08
Оценка:
Здравствуйте, SeRya, Вы писали:

SR>Идея учета размерности и других свойст велечин (здесь — диапазон), конечно, интересна, но не стеляешь ли ты из пушки по воробьям?


Если речь идёт о программе, которыую пишет один программист и забывает о ней, то, конечно, да. А если о проекте, который пишет несколько человек несколько лет, причём большая часть из них — студетны то — нет.

SR>Судя по тому, что у тебя Discount — это класс, а discount — имеет тип double, ты не до конца понимаешь то, что хочешь или по крайней мере путаешься в терминологии.


А что такого?

SR>Про комментарий я вообще молчу. Ощущение такое, что он написан для тех, кто не знает синтаксиса конструктора и ссылочного типа


У людей, которых заставляют комментировать по стандарту, — это больная тема Хотя это вроде на стандарт не похоже...

Меня прикалывает такие комметарии:

/** Массив */
class Vector
{

...
/** Получить размер массива
* @return Размер массива
*/
int getSize();

...
};


SR>Если у тебя числа хранятся как попало и где попало преобразуются в Discount, то ошибиться легко. Но если информация о представлении Discount инкапсулирована, то проблем скорее всего не возникнет.


Ну так он о том говорит, что бы её инкапсулировать, а не передавать через double.
Ну у него-то она может быть и инкапсулирована, а у студента, который будет через пять лет это дописывать не будет инкапсулирована

В общем я — за!


з.ы. про студентов — это я собирательно, просьба не обижаться, сам — студент

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: В поисках семантической корректности
От: remark Россия http://www.1024cores.net/
Дата: 04.08.05 15:21
Оценка:
Здравствуйте, Нахлобуч, Вы писали:

Н>Я тут в этих самых "поисках" и пребываю, собственно. Очень, надо сказать, гадостная вешь. К примеру:


Н ...
Н>Использует кто-нибудь что-нибудь подобное?

Я когда-то использовал подобное.
Писал проект, в котором было много всякой математической всячины — скалярные величины, векторы, матрицы, множества. Все они имели соответственно различное семантическое значение, т.е. "матрица S" — это совсем не тоже самое, что "матрица L"

Тогда я делал так:

typedef int Value;
typedef int Dimension;
typedef std::vector<std::vector<Value> > MatrixValue;
typedef std::vector<std::vector<Dimension> > MatrixDimension;

class MatrixS : public MatrixValue
{
...
};

class MatrixL : public MatrixDimension
{
...
};

Соответственно типы матриц, векторов и т.д. у меня различал компилятор, хотя фактически они имели одинаковый тип — матрица. До скалярных типов я правда не дошёл, т.к. из практически не было, хотя Value и Dimension подсказывал msvc.

Только кострукторы надо опредеять, через шаблоны конечно надо.

В общем, большом проекте идея достаточно здравая.

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.