Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Type Requirements and User-defined-types support

Boost , Chapter 1. Boost.NumericConversion , Chapter 1. Boost.NumericConversion

Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Как арифметические (встроенные), так и определяемые пользователем числовые типы требуют надлежащей специализации<std::numeric_limits<>>(то есть с интегральными константами).

Библиотека использует<std::numeric_limits<T>::is_specialized>для определения того, является ли тип встроенным или определенным пользователем, и<std::numeric_limits<T>::is_integer>,<std::numeric_limits<T>::is_signed>для определения того, является ли тип целым или плавающей точкой; и является ли он подписанным / неподписанным.

Политика по умолчанию<Float2IntRounder>использует неквалифицированные вызовы к функциям<floor()>и<ceil()>; но стандартные функции вводятся в область применения директивой использования:

using std::floor ; return floor(s);

Поэтому для встроенных типов арифметики будут использоваться функции std. Определенные пользователем типы должны предоставлять перегруженные версии этих функций, чтобы использовать более круглые политики по умолчанию. Если эти перегрузки определены в зависимости от аргумента пространства имен пользователя, поиск (ADL) должен их найти, но если у вашего компилятора слабая ADL, вам может потребоваться поместить эти функции в другое место или написать свою собственную политику округления.

По умолчанию<Trunc<>>политика округления должна определять, является ли исходное значение положительным или нет, и для этого она оценивает выражение<s <static_cast<S>(0)>. Таким образом, определяемые пользователем типы требуют видимого<operator<>для использования политики<Trunc<>>(по умолчанию).

Conversion Traits

Если пользовательский определенный тип участвует в преобразовании, топредполагается, что UDT имеетболее широкий диапазон, чем любой встроенный тип, и, следовательно, значения некоторых<converter_traits<>>участников являются жесткими независимо от реальности. Нижеследующая таблица резюмирует это:

  • <Target=>УДТи<Source=>встроенные
    • <subranged=false>
    • <supertype=Target>
    • <subtype=Source>
  • <Target=>встроенныйи<Source=>UDT
    • <subranged=true>
    • <supertype=Source>
    • <subtype=Target>
  • <Target=>УДТи<Source=>УДТ
    • <subranged=false>
    • <supertype=Target>
    • <subtype=Source>

<Traits>член<udt_mixture>может быть использован для определения того, участвует ли UDT, и для определения действительности других членов, как показано выше.

Range Checking

Поскольку определяемые пользователем числовые типы могут иметь особые диапазоны (например, неограниченный диапазон), эта библиотека не пытается предоставить значимую логику проверки диапазона, когда UDT участвуют в преобразовании. Поэтому, если ни Target, ни Source не являются встроенными типами, функция проверки диапазона<converter<>>автоматически отключается. Тем не менее, можно предоставить пользовательскую проверку диапазона. См.Специальная политика

Существует два компонента класса<converter<>>, которые могут потребовать особого поведения, если речь идет об определенных пользователях: проверка диапазона и конверсия RAW.

Когда и Target, и Source являются встроенными типами, класс преобразователя использует внутреннюю логику проверки диапазона, которая оптимизирована и настроена для комбинированных свойств типов.

Однако эта внутренняя логика отключена, когда любой тип определен пользователем. В этом случае пользователь может указатьвнешнююполитику проверки диапазона, которая будет использоваться вместо внутреннего кода. См.numeric_cast_traitsдля подробной информации об использовании UDT с<numeric_cast>.

Класс преобразователя выполняет фактическое преобразование с использованием политики Raw Converter. По умолчанию преобразователь просто выполняет<static_cast<Target>(source)>.

Однако, если UDT участвует,<static_cast>может не работать. В этом случае пользователь может реализовать и пройти другую политику конвертера. См.Политика RawConverterдля деталей.

Чтобы использовать UDT с<numeric_cast>, пользователь должен определить специализацию<numeric_cast_traits>на UDT для каждого преобразования. Вот пример специализации для преобразования между UDT и любым другим типом:

namespace boost { namespace numeric {
template <typename Source>
struct numeric_cast_traits<UDT, Source>
{
    typedef conversion_traits<UDT, Source>      conv_traits;
    //! The following are required:
    typedef YourOverflowHandlerPolicy           overflow_policy;
    typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy;
    typedef YourFloat2IntRounderPolicy<Source>  rounding_policy;
};
template <typename Target>
struct numeric_cast_traits<Target, UDT>
{
    typedef conversion_traits<Target, UDT>      conv_traits;
    //! The following are required:
    typedef YourOverflowHandlerPolicy           overflow_policy;
    typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy;
    typedef YourFloat2IntRounderPolicy<UDT>     rounding_policy;
};
}}//namespace boost::numeric;

Эти специализации уже определены с значениями по умолчанию для встроенных числовых типов. Отключить генерацию специализаций для встроенных типов можно, определив<BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS>. Подробнее об определении таможенной политики см.Политика конвертеров.

Вот полный пример того, как определить пользовательский UDT для использования с<numeric_cast>:

//! Define a simple custom number
struct Double
    :   boost::ordered_field_operators
        <
            Double
          , boost::ordered_field_operators2< Double, long double
          , boost::ordered_field_operators2< Double, double
          , boost::ordered_field_operators2< Double, float
          , boost::ordered_field_operators2< Double, int
          , boost::ordered_field_operators2< Double, unsigned int
          , boost::ordered_field_operators2< Double, long
          , boost::ordered_field_operators2< Double, unsigned long
          , boost::ordered_field_operators2< Double, long long
          , boost::ordered_field_operators2< Double, unsigned long long
          , boost::ordered_field_operators2< Double, char
          , boost::ordered_field_operators2< Double, unsigned char
          , boost::ordered_field_operators2< Double, short
          , boost::ordered_field_operators2< Double, unsigned short
        > > > > > > > > > > > > > >
{
    Double()
        : v(0)
    {}
    template <typename T>
    explicit Double( T v )
        : v(static_cast<double>(v))
    {}
    template <typename T>
    Double& operator= ( T t )
    {
        v = static_cast<double>(t);
        return *this;
    }
    bool operator < ( const Double& rhs ) const
    {
        return v < rhs.v;
    }
    template <typename T>
    bool operator < ( T rhs ) const
    {
        return v < static_cast<double>(rhs);
    }
    bool operator > ( const Double& rhs ) const
    {
        return v > rhs.v;
    }
    template <typename T>
    bool operator > ( T rhs ) const
    {
        return v > static_cast<double>(rhs);
    }
    bool operator ==( const Double& rhs ) const
    {
        return v == rhs.v;
    }
    template <typename T>
    bool operator == ( T rhs ) const
    {
        return v == static_cast<double>(rhs);
    }
    bool operator !() const
    {
        return v == 0;
    }
    Double operator -() const
    {
        return Double(-v);
    }
    Double& operator +=( const Double& t )
    {
        v += t.v;
        return *this;
    }
    template <typename T>
    Double& operator +=( T t )
    {
        v += static_cast<double>(t);
        return *this;
    }
    Double& operator -=( const Double& t )
    {
        v -= t.v;
        return *this;
    }
    template <typename T>
    Double& operator -=( T t )
    {
        v -= static_cast<double>(t);
        return *this;
    }
    Double& operator *= ( const Double& factor )
    {
        v *= factor.v;
        return *this;
    }
    template <typename T>
    Double& operator *=( T t )
    {
        v *= static_cast<double>(t);
        return *this;
    }
    Double& operator /= (const Double& divisor)
    {
        v /= divisor.v;
        return *this;
    }
    template <typename T>
    Double& operator /=( T t )
    {
         v /= static_cast<double>(t);
        return (*this);
    }
    double v;
};
//! Define numeric_limits for the custom type.
namespace std
{
    template<>
    class numeric_limits<Double> : public numeric_limits<double>
    {
    public:
        //! Limit our Double to a range of +/- 100.0
        static Double (min)()
        {
            return Double(1.e-2);
        }
        static Double (max)()
        {
            return Double(1.e2);
        }
        static Double epsilon()
        {
            return Double( std::numeric_limits<double>::epsilon() );
        }
    };
}
//! Define range checking and overflow policies.
namespace custom
{
    //! Define a custom range checker
    template<typename Traits, typename OverFlowHandler>
    struct range_checker
    {
        typedef typename Traits::argument_type argument_type ;
        typedef typename Traits::source_type S;
        typedef typename Traits::target_type T;
        //! Check range of integral types.
        static boost::numeric::range_check_result out_of_range( argument_type s )
        {
            using namespace boost::numeric;
            if( s > bounds<T>::highest() )
                return cPosOverflow;
            else if( s < bounds<T>::lowest() )
                return cNegOverflow;
            else
                return cInRange;
        }
        static void validate_range ( argument_type s )
        {
            BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_bounded );
            OverFlowHandler()( out_of_range(s) );
        }
    };
    //! Overflow handler
    struct positive_overflow{};
    struct negative_overflow{};
    struct overflow_handler
    {
        void operator() ( boost::numeric::range_check_result r )
        {
            using namespace boost::numeric;
            if( r == cNegOverflow )
                throw negative_overflow() ;
            else if( r == cPosOverflow )
                throw positive_overflow() ;
        }
    };
    //! Define a rounding policy and specialize on the custom type.
    template<class S>
    struct Ceil : boost::numeric::Ceil<S>{};
    template<>
    struct Ceil<Double>
    {
      typedef Double source_type;
      typedef Double const& argument_type;
      static source_type nearbyint ( argument_type s )
      {
#if !defined(BOOST_NO_STDC_NAMESPACE)
          using std::ceil ;
#endif
          return Double( ceil(s.v) );
      }
      typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style;
    };
    //! Define a rounding policy and specialize on the custom type.
    template<class S>
    struct Trunc: boost::numeric::Trunc<S>{};
    template<>
    struct Trunc<Double>
    {
      typedef Double source_type;
      typedef Double const& argument_type;
      static source_type nearbyint ( argument_type s )
      {
#if !defined(BOOST_NO_STDC_NAMESPACE)
          using std::floor;
#endif
          return Double( floor(s.v) );
      }
      typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style;
    };
}//namespace custom;
namespace boost { namespace numeric {
    //! Define the numeric_cast_traits specializations on the custom type.
    template <typename S>
    struct numeric_cast_traits<Double, S>
    {
        typedef custom::overflow_handler                         overflow_policy;
        typedef custom::range_checker
                <
                    boost::numeric::conversion_traits<Double, S>
                  , overflow_policy
                >                                                range_checking_policy;
        typedef boost::numeric::Trunc<S>                         rounding_policy;
    };
    template <typename T>
    struct numeric_cast_traits<T, Double>
    {
        typedef custom::overflow_handler                         overflow_policy;
        typedef custom::range_checker
                <
                    boost::numeric::conversion_traits<T, Double>
                  , overflow_policy
                >                                                range_checking_policy;
        typedef custom::Trunc<Double>                            rounding_policy;
    };
    //! Define the conversion from the custom type to built-in types and vice-versa.
    template<typename T>
    struct raw_converter< conversion_traits< T, Double > >
    {
        static T low_level_convert ( const Double& n )
        {
            return static_cast<T>( n.v );
        }
    };
    template<typename S>
    struct raw_converter< conversion_traits< Double, S > >
    {
        static Double low_level_convert ( const S& n )
        {
            return Double(n);
        }
    };
}}//namespace boost::numeric;

PrevUpHomeNext

Статья Type Requirements and User-defined-types support раздела Chapter 1. Boost.NumericConversion Chapter 1. Boost.NumericConversion может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 1. Boost.NumericConversion ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 20:45:23/0.031345129013062/1