Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:23

0001 ///////////////////////////////////////////////////////////////////////////////
0002 //  Copyright 2011 John Maddock. Distributed under the Boost
0003 //  Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_MP_NUMBER_BASE_HPP
0007 #define BOOST_MP_NUMBER_BASE_HPP
0008 
0009 #include <climits>
0010 #include <ios>
0011 #include <string>
0012 #include <limits>
0013 #include <type_traits>
0014 #include <stdexcept>
0015 #include <tuple>
0016 #include <boost/multiprecision/detail/standalone_config.hpp>
0017 #include <boost/multiprecision/fwd.hpp>
0018 #include <boost/multiprecision/traits/transcendental_reduction_type.hpp>
0019 #include <boost/multiprecision/traits/std_integer_traits.hpp>
0020 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0021 
0022 #ifdef BOOST_MSVC
0023 #pragma warning(push)
0024 #pragma warning(disable : 4307)
0025 #pragma warning(pop)
0026 #endif
0027 
0028 #ifndef BOOST_MP_STANDALONE
0029 #include <boost/lexical_cast.hpp>
0030 #include <boost/core/nvp.hpp>
0031 #endif
0032 
0033 #ifdef BOOST_MP_MATH_AVAILABLE
0034 #include <boost/math/tools/complex.hpp>
0035 #endif
0036 
0037 // We now require C++11.
0038 #include <boost/multiprecision/detail/check_cpp11_config.hpp>
0039 
0040 #if defined(NDEBUG) && !defined(_DEBUG)
0041 #define BOOST_MP_FORCEINLINE BOOST_FORCEINLINE
0042 #else
0043 #define BOOST_MP_FORCEINLINE inline
0044 #endif
0045 
0046 //
0047 // Thread local storage:
0048 // Note fails on Mingw, see https://sourceforge.net/p/mingw-w64/bugs/527/
0049 //
0050 #if defined(BOOST_NO_CXX11_THREAD_LOCAL)
0051 #define BOOST_MP_THREAD_LOCAL
0052 #elif !(defined(__MINGW32__) && (defined(__GNUC__) && (__GNUC__ < 9)) && !defined(__clang__))
0053 #define BOOST_MP_THREAD_LOCAL thread_local
0054 #define BOOST_MP_USING_THREAD_LOCAL
0055 #else
0056 #pragma GCC warning "thread_local on mingw is broken, please use MSys mingw gcc-9 or later, see https://sourceforge.net/p/mingw-w64/bugs/527/"
0057 #define BOOST_MP_THREAD_LOCAL
0058 #endif
0059 
0060 #ifdef __has_include
0061 # if __has_include(<version>)
0062 #  include <version>
0063 #  ifdef __cpp_lib_is_constant_evaluated
0064 #   include <type_traits>
0065 #   define BOOST_MP_HAS_IS_CONSTANT_EVALUATED
0066 #  endif
0067 # endif
0068 #endif
0069 
0070 #ifdef __has_builtin
0071 #if __has_builtin(__builtin_is_constant_evaluated) && !defined(BOOST_NO_CXX14_CONSTEXPR) && !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX)
0072 #define BOOST_MP_HAS_BUILTIN_IS_CONSTANT_EVALUATED
0073 #endif
0074 #endif
0075 //
0076 // MSVC also supports __builtin_is_constant_evaluated if it's recent enough:
0077 //
0078 #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 192528326)
0079 #  define BOOST_MP_HAS_BUILTIN_IS_CONSTANT_EVALUATED
0080 #endif
0081 //
0082 // As does GCC-9:
0083 //
0084 #if defined(BOOST_GCC) && !defined(BOOST_NO_CXX14_CONSTEXPR) && (__GNUC__ >= 9) && !defined(BOOST_MP_HAS_BUILTIN_IS_CONSTANT_EVALUATED)
0085 #  define BOOST_MP_HAS_BUILTIN_IS_CONSTANT_EVALUATED
0086 #endif
0087 
0088 #if defined(BOOST_MP_HAS_IS_CONSTANT_EVALUATED) && !defined(BOOST_NO_CXX14_CONSTEXPR)
0089 #  define BOOST_MP_IS_CONST_EVALUATED(x) std::is_constant_evaluated()
0090 #elif defined(BOOST_MP_HAS_BUILTIN_IS_CONSTANT_EVALUATED)
0091 #  define BOOST_MP_IS_CONST_EVALUATED(x) __builtin_is_constant_evaluated()
0092 #elif !defined(BOOST_NO_CXX14_CONSTEXPR) && defined(BOOST_GCC) && (__GNUC__ >= 6)
0093 #  define BOOST_MP_IS_CONST_EVALUATED(x) __builtin_constant_p(x)
0094 #else
0095 #  define BOOST_MP_NO_CONSTEXPR_DETECTION
0096 #endif
0097 
0098 
0099 #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
0100 #  define BOOST_CXX14_CONSTEXPR_IF_DETECTION
0101 #else
0102 #  define BOOST_CXX14_CONSTEXPR_IF_DETECTION constexpr
0103 #endif
0104 
0105 #ifdef BOOST_MSVC
0106 #pragma warning(push)
0107 #pragma warning(disable : 6326)
0108 #endif
0109 
0110 namespace boost {
0111 namespace multiprecision {
0112 
0113 
0114 enum struct variable_precision_options : signed char
0115 {
0116    assume_uniform_precision = -1,
0117    preserve_target_precision = 0,
0118    preserve_source_precision = 1,
0119    preserve_component_precision = 2,
0120    preserve_related_precision = 3,
0121    preserve_all_precision = 4,
0122 };
0123 
0124 inline constexpr bool operator==(variable_precision_options a, variable_precision_options b)
0125 {
0126    return static_cast<unsigned>(a) == static_cast<unsigned>(b);
0127 }
0128 
0129 template <class T>
0130 struct is_et_number : public std::integral_constant<bool, false>
0131 {};
0132 
0133 template <class Backend>
0134 struct is_et_number<number<Backend, et_on> > : public std::integral_constant<bool, true>
0135 {};
0136 
0137 template <class T>
0138 struct is_no_et_number : public std::integral_constant<bool, false>
0139 {};
0140 
0141 template <class Backend>
0142 struct is_no_et_number<number<Backend, et_off> > : public std::integral_constant<bool, true>
0143 {};
0144 
0145 template <class T>
0146 struct is_number_expression : public std::integral_constant<bool, false>
0147 {};
0148 
0149 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
0150 struct is_number_expression<detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > : public std::integral_constant<bool, true>
0151 {};
0152 
0153 template <class T, class Num>
0154 struct is_compatible_arithmetic_type
0155     : public std::integral_constant<bool, 
0156           std::is_convertible<T, Num>::value && !std::is_same<T, Num>::value && !is_number_expression<T>::value>
0157 {};
0158 
0159 namespace detail {
0160 //
0161 // Workaround for missing abs(long long) and abs(__int128) on some compilers:
0162 //
0163 template <class T>
0164 constexpr typename std::enable_if<(boost::multiprecision::detail::is_signed<T>::value || std::is_floating_point<T>::value), T>::type abs(T t) noexcept
0165 {
0166    // This strange expression avoids a hardware trap in the corner case
0167    // that val is the most negative value permitted in long long.
0168    // See https://svn.boost.org/trac/boost/ticket/9740.
0169    return t < 0 ? T(1u) + T(-(t + 1)) : t;
0170 }
0171 template <class T>
0172 constexpr typename std::enable_if<boost::multiprecision::detail::is_unsigned<T>::value, T>::type abs(T t) noexcept
0173 {
0174    return t;
0175 }
0176 
0177 #define BOOST_MP_USING_ABS using boost::multiprecision::detail::abs;
0178 
0179 template <class T>
0180 constexpr typename std::enable_if<(boost::multiprecision::detail::is_signed<T>::value || std::is_floating_point<T>::value), typename boost::multiprecision::detail::make_unsigned<T>::type>::type unsigned_abs(T t) noexcept
0181 {
0182    // This strange expression avoids a hardware trap in the corner case
0183    // that val is the most negative value permitted in long long.
0184    // See https://svn.boost.org/trac/boost/ticket/9740.
0185    return t < 0 ? static_cast<typename boost::multiprecision::detail::make_unsigned<T>::type>(1u) + static_cast<typename boost::multiprecision::detail::make_unsigned<T>::type>(-(t + 1)) : static_cast<typename boost::multiprecision::detail::make_unsigned<T>::type>(t);
0186 }
0187 template <class T>
0188 constexpr typename std::enable_if<boost::multiprecision::detail::is_unsigned<T>::value, T>::type unsigned_abs(T t) noexcept
0189 {
0190    return t;
0191 }
0192 
0193 template <class T>
0194 struct bits_of
0195 {
0196    static_assert(boost::multiprecision::detail::is_integral<T>::value || std::is_enum<T>::value || std::numeric_limits<T>::is_specialized, "Failed integer size check");
0197    static constexpr unsigned value =
0198        std::numeric_limits<T>::is_specialized ? std::numeric_limits<T>::digits
0199                                               : sizeof(T) * CHAR_BIT - (boost::multiprecision::detail::is_signed<T>::value ? 1 : 0);
0200 };
0201 
0202 #if defined(_GLIBCXX_USE_FLOAT128) && defined(BOOST_GCC) && !defined(__STRICT_ANSI__)
0203 #define BOOST_MP_BITS_OF_FLOAT128_DEFINED
0204 template <>
0205 struct bits_of<float128_type>
0206 {
0207    static constexpr unsigned value = 113;
0208 };
0209 #endif
0210 
0211 template <int b>
0212 struct has_enough_bits
0213 {
0214    template <class T>
0215    struct type : public std::integral_constant<bool, bits_of<T>::value >= b>
0216    {};
0217 };
0218 
0219 template <class Tuple, int i, int digits, bool = (i >= std::tuple_size<Tuple>::value)>
0220 struct find_index_of_large_enough_type
0221 {
0222    static constexpr int value = bits_of<typename std::tuple_element<static_cast<std::size_t>(i), Tuple>::type>::value >= digits ? i : find_index_of_large_enough_type<Tuple, i + 1, digits>::value;
0223 };
0224 template <class Tuple, int i, int digits>
0225 struct find_index_of_large_enough_type<Tuple, i, digits, true>
0226 {
0227    static constexpr int value = INT_MAX;
0228 };
0229 
0230 template <int index, class Tuple, class Fallback, bool = (std::tuple_size<Tuple>::value <= index)>
0231 struct dereference_tuple
0232 {
0233    using type = typename std::tuple_element<static_cast<std::size_t>(index), Tuple>::type;
0234 };
0235 template <int index, class Tuple, class Fallback>
0236 struct dereference_tuple<index, Tuple, Fallback, true>
0237 {
0238    using type = Fallback;
0239 };
0240 
0241 template <class Val, class Backend, class Tag>
0242 struct canonical_imp
0243 {
0244    using type = typename std::remove_cv<typename std::decay<const Val>::type>::type;
0245 };
0246 template <class B, class Backend, class Tag>
0247 struct canonical_imp<number<B, et_on>, Backend, Tag>
0248 {
0249    using type = B;
0250 };
0251 template <class B, class Backend, class Tag>
0252 struct canonical_imp<number<B, et_off>, Backend, Tag>
0253 {
0254    using type = B;
0255 };
0256 #ifdef __SUNPRO_CC
0257 template <class B, class Backend>
0258 struct canonical_imp<number<B, et_on>, Backend, std::integral_constant<int, 3> >
0259 {
0260    using type = B;
0261 };
0262 template <class B, class Backend>
0263 struct canonical_imp<number<B, et_off>, Backend, std::integral_constant<int, 3> >
0264 {
0265    using type = B;
0266 };
0267 #endif
0268 template <class Val, class Backend>
0269 struct canonical_imp<Val, Backend, std::integral_constant<int, 0> >
0270 {
0271    static constexpr int index = find_index_of_large_enough_type<typename Backend::signed_types, 0, bits_of<Val>::value>::value;
0272    using type = typename dereference_tuple<index, typename Backend::signed_types, Val>::type;
0273 };
0274 template <class Val, class Backend>
0275 struct canonical_imp<Val, Backend, std::integral_constant<int, 1> >
0276 {
0277    static constexpr int index = find_index_of_large_enough_type<typename Backend::unsigned_types, 0, bits_of<Val>::value>::value;
0278    using type = typename dereference_tuple<index, typename Backend::unsigned_types, Val>::type;
0279 };
0280 template <class Val, class Backend>
0281 struct canonical_imp<Val, Backend, std::integral_constant<int, 2> >
0282 {
0283    static constexpr int index = find_index_of_large_enough_type<typename Backend::float_types, 0, bits_of<Val>::value>::value;
0284    using type = typename dereference_tuple<index, typename Backend::float_types, Val>::type;
0285 };
0286 template <class Val, class Backend>
0287 struct canonical_imp<Val, Backend, std::integral_constant<int, 3> >
0288 {
0289    using type = const char*;
0290 };
0291 template <class Val, class Backend>
0292 struct canonical_imp<Val, Backend, std::integral_constant<int, 4> >
0293 {
0294    using underlying = typename std::underlying_type<Val>::type;
0295    using tag = typename std::conditional<boost::multiprecision::detail::is_signed<Val>::value, std::integral_constant<int, 0>, std::integral_constant<int, 1>>::type;
0296    using type = typename canonical_imp<underlying, Backend, tag>::type;
0297 };
0298 
0299 template <class Val, class Backend>
0300 struct canonical
0301 {
0302    using tag_type = typename std::conditional<
0303        boost::multiprecision::detail::is_signed<Val>::value && boost::multiprecision::detail::is_integral<Val>::value,
0304        std::integral_constant<int, 0>,
0305        typename std::conditional<
0306            boost::multiprecision::detail::is_unsigned<Val>::value,
0307            std::integral_constant<int, 1>,
0308            typename std::conditional<
0309                std::is_floating_point<Val>::value,
0310                std::integral_constant<int, 2>,
0311                typename std::conditional<
0312                    (std::is_convertible<Val, const char*>::value || std::is_same<Val, std::string>::value),
0313                    std::integral_constant<int, 3>,
0314                    typename std::conditional<
0315                      std::is_enum<Val>::value,
0316                      std::integral_constant<int, 4>,
0317                      std::integral_constant<int, 5> >::type>::type>::type>::type>::type;
0318 
0319    using type = typename canonical_imp<Val, Backend, tag_type>::type;
0320 };
0321 
0322 struct terminal
0323 {};
0324 struct negate
0325 {};
0326 struct plus
0327 {};
0328 struct minus
0329 {};
0330 struct multiplies
0331 {};
0332 struct divides
0333 {};
0334 struct modulus
0335 {};
0336 struct shift_left
0337 {};
0338 struct shift_right
0339 {};
0340 struct bitwise_and
0341 {};
0342 struct bitwise_or
0343 {};
0344 struct bitwise_xor
0345 {};
0346 struct bitwise_complement
0347 {};
0348 struct add_immediates
0349 {};
0350 struct subtract_immediates
0351 {};
0352 struct multiply_immediates
0353 {};
0354 struct divide_immediates
0355 {};
0356 struct modulus_immediates
0357 {};
0358 struct bitwise_and_immediates
0359 {};
0360 struct bitwise_or_immediates
0361 {};
0362 struct bitwise_xor_immediates
0363 {};
0364 struct complement_immediates
0365 {};
0366 struct function
0367 {};
0368 struct multiply_add
0369 {};
0370 struct multiply_subtract
0371 {};
0372 
0373 template <class T>
0374 struct backend_type;
0375 
0376 template <class T, expression_template_option ExpressionTemplates>
0377 struct backend_type<number<T, ExpressionTemplates> >
0378 {
0379    using type = T;
0380 };
0381 
0382 template <class tag, class A1, class A2, class A3, class A4>
0383 struct backend_type<expression<tag, A1, A2, A3, A4> >
0384 {
0385    using type = typename backend_type<typename expression<tag, A1, A2, A3, A4>::result_type>::type;
0386 };
0387 
0388 template <class T1, class T2>
0389 struct combine_expression
0390 {
0391    using type = decltype(T1() + T2());
0392 };
0393 
0394 template <class T1, expression_template_option ExpressionTemplates, class T2>
0395 struct combine_expression<number<T1, ExpressionTemplates>, T2>
0396 {
0397    using type = number<T1, ExpressionTemplates>;
0398 };
0399 
0400 template <class T1, class T2, expression_template_option ExpressionTemplates>
0401 struct combine_expression<T1, number<T2, ExpressionTemplates> >
0402 {
0403    using type = number<T2, ExpressionTemplates>;
0404 };
0405 
0406 template <class T, expression_template_option ExpressionTemplates>
0407 struct combine_expression<number<T, ExpressionTemplates>, number<T, ExpressionTemplates> >
0408 {
0409    using type = number<T, ExpressionTemplates>;
0410 };
0411 
0412 template <class T1, expression_template_option ExpressionTemplates1, class T2, expression_template_option ExpressionTemplates2>
0413 struct combine_expression<number<T1, ExpressionTemplates1>, number<T2, ExpressionTemplates2> >
0414 {
0415    using type = typename std::conditional<
0416        std::is_convertible<number<T2, ExpressionTemplates2>, number<T1, ExpressionTemplates2> >::value,
0417        number<T1, ExpressionTemplates1>,
0418        number<T2, ExpressionTemplates2> >::type;
0419 };
0420 
0421 template <class T>
0422 struct arg_type
0423 {
0424    using type = expression<terminal, T>;
0425 };
0426 
0427 template <class Tag, class Arg1, class Arg2, class Arg3, class Arg4>
0428 struct arg_type<expression<Tag, Arg1, Arg2, Arg3, Arg4> >
0429 {
0430    using type = expression<Tag, Arg1, Arg2, Arg3, Arg4>;
0431 };
0432 
0433 struct unmentionable
0434 {
0435    unmentionable* proc() { return nullptr; }
0436 };
0437 
0438 typedef unmentionable* (unmentionable::*unmentionable_type)();
0439 
0440 template <class T, bool b>
0441 struct expression_storage_base
0442 {
0443    using type = const T&;
0444 };
0445 
0446 template <class T>
0447 struct expression_storage_base<T, true>
0448 {
0449    using type = T;
0450 };
0451 
0452 template <class T>
0453 struct expression_storage : public expression_storage_base<T, boost::multiprecision::detail::is_arithmetic<T>::value>
0454 {};
0455 
0456 template <class T>
0457 struct expression_storage<T*>
0458 {
0459    using type = T*;
0460 };
0461 
0462 template <class T>
0463 struct expression_storage<const T*>
0464 {
0465    using type = const T*;
0466 };
0467 
0468 template <class tag, class A1, class A2, class A3, class A4>
0469 struct expression_storage<expression<tag, A1, A2, A3, A4> >
0470 {
0471    using type = expression<tag, A1, A2, A3, A4>;
0472 };
0473 
0474 template <class tag, class Arg1>
0475 struct expression<tag, Arg1, void, void, void>
0476 {
0477    using arity = std::integral_constant<int, 1>                   ;
0478    using left_type = typename arg_type<Arg1>::type  ;
0479    using left_result_type = typename left_type::result_type;
0480    using result_type = typename left_type::result_type;
0481    using tag_type = tag                            ;
0482 
0483    explicit BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a) : arg(a) {}
0484    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg(e.arg) {}
0485 
0486    //
0487    // If we have static_assert we can give a more useful error message
0488    // than if we simply have no operator defined at all:
0489    //
0490    template <class Other>
0491    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
0492    {
0493       // This should always fail:
0494       static_assert(sizeof(Other) == INT_MAX, "You can not assign to a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0495       return *this;
0496    }
0497    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
0498    {
0499       // This should always fail:
0500       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0501       return *this;
0502    }
0503    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
0504    {
0505       // This should always fail:
0506       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0507       return *this;
0508    }
0509    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
0510    {
0511       // This should always fail:
0512       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0513       return *this;
0514    }
0515    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
0516    {
0517       // This should always fail:
0518       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0519       return *this;
0520    }
0521    template <class Other>
0522    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
0523    {
0524       // This should always fail:
0525       static_assert(sizeof(Other) == INT_MAX, "You can not use operator+= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0526       return *this;
0527    }
0528    template <class Other>
0529    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
0530    {
0531       // This should always fail:
0532       static_assert(sizeof(Other) == INT_MAX, "You can not use operator-= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0533       return *this;
0534    }
0535    template <class Other>
0536    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
0537    {
0538       // This should always fail:
0539       static_assert(sizeof(Other) == INT_MAX, "You can not use operator*= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0540       return *this;
0541    }
0542    template <class Other>
0543    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
0544    {
0545       // This should always fail:
0546       static_assert(sizeof(Other) == INT_MAX, "You can not use operator/= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0547       return *this;
0548    }
0549    template <class Other>
0550    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
0551    {
0552       // This should always fail:
0553       static_assert(sizeof(Other) == INT_MAX, "You can not use operator%= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0554       return *this;
0555    }
0556    template <class Other>
0557    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
0558    {
0559       // This should always fail:
0560       static_assert(sizeof(Other) == INT_MAX, "You can not use operator|= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0561       return *this;
0562    }
0563    template <class Other>
0564    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
0565    {
0566       // This should always fail:
0567       static_assert(sizeof(Other) == INT_MAX, "You can not use operator&= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0568       return *this;
0569    }
0570    template <class Other>
0571    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
0572    {
0573       // This should always fail:
0574       static_assert(sizeof(Other) == INT_MAX, "You can not use operator^= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0575       return *this;
0576    }
0577    template <class Other>
0578    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
0579    {
0580       // This should always fail:
0581       static_assert(sizeof(Other) == INT_MAX, "You can not use operator<<= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0582       return *this;
0583    }
0584    template <class Other>
0585    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
0586    {
0587       // This should always fail:
0588       static_assert(sizeof(Other) == INT_MAX, "You can not use operator>>= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0589       return *this;
0590    }
0591 
0592    BOOST_MP_CXX14_CONSTEXPR left_type left() const
0593    {
0594       return left_type(arg);
0595    }
0596 
0597    BOOST_MP_CXX14_CONSTEXPR const Arg1& left_ref() const noexcept { return arg; }
0598 
0599    static constexpr unsigned depth = left_type::depth + 1;
0600    template <class T
0601 #ifndef __SUNPRO_CC
0602              ,
0603              typename std::enable_if<!is_number<T>::value && !std::is_convertible<result_type, T const&>::value && std::is_constructible<T, result_type>::value, int>::type = 0
0604 #endif
0605              >
0606    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
0607    {
0608       return static_cast<T>(static_cast<result_type>(*this));
0609    }
0610    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
0611    {
0612       result_type r(*this);
0613       return static_cast<bool>(r);
0614    }
0615 
0616    template <class T>
0617    BOOST_MP_CXX14_CONSTEXPR T convert_to()
0618    {
0619       result_type r(*this);
0620       return r.template convert_to<T>();
0621    }
0622 
0623  private:
0624    typename expression_storage<Arg1>::type arg;
0625    expression&                             operator=(const expression&);
0626 };
0627 
0628 template <class Arg1>
0629 struct expression<terminal, Arg1, void, void, void>
0630 {
0631    using arity = std::integral_constant<int, 0>;
0632    using result_type = Arg1        ;
0633    using tag_type = terminal    ;
0634 
0635    explicit BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a) : arg(a) {}
0636    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg(e.arg) {}
0637 
0638    //
0639    // If we have static_assert we can give a more useful error message
0640    // than if we simply have no operator defined at all:
0641    //
0642    template <class Other>
0643    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
0644    {
0645       // This should always fail:
0646       static_assert(sizeof(Other) == INT_MAX, "You can not assign to a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0647       return *this;
0648    }
0649    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
0650    {
0651       // This should always fail:
0652       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0653       return *this;
0654    }
0655    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
0656    {
0657       // This should always fail:
0658       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0659       return *this;
0660    }
0661    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
0662    {
0663       // This should always fail:
0664       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0665       return *this;
0666    }
0667    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
0668    {
0669       // This should always fail:
0670       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0671       return *this;
0672    }
0673    template <class Other>
0674    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
0675    {
0676       // This should always fail:
0677       static_assert(sizeof(Other) == INT_MAX, "You can not use operator+= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0678       return *this;
0679    }
0680    template <class Other>
0681    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
0682    {
0683       // This should always fail:
0684       static_assert(sizeof(Other) == INT_MAX, "You can not use operator-= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0685       return *this;
0686    }
0687    template <class Other>
0688    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
0689    {
0690       // This should always fail:
0691       static_assert(sizeof(Other) == INT_MAX, "You can not use operator*= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0692       return *this;
0693    }
0694    template <class Other>
0695    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
0696    {
0697       // This should always fail:
0698       static_assert(sizeof(Other) == INT_MAX, "You can not use operator/= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0699       return *this;
0700    }
0701    template <class Other>
0702    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
0703    {
0704       // This should always fail:
0705       static_assert(sizeof(Other) == INT_MAX, "You can not use operator%= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0706       return *this;
0707    }
0708    template <class Other>
0709    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
0710    {
0711       // This should always fail:
0712       static_assert(sizeof(Other) == INT_MAX, "You can not use operator|= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0713       return *this;
0714    }
0715    template <class Other>
0716    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
0717    {
0718       // This should always fail:
0719       static_assert(sizeof(Other) == INT_MAX, "You can not use operator&= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0720       return *this;
0721    }
0722    template <class Other>
0723    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
0724    {
0725       // This should always fail:
0726       static_assert(sizeof(Other) == INT_MAX, "You can not use operator^= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0727       return *this;
0728    }
0729    template <class Other>
0730    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
0731    {
0732       // This should always fail:
0733       static_assert(sizeof(Other) == INT_MAX, "You can not use operator<<= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0734       return *this;
0735    }
0736    template <class Other>
0737    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
0738    {
0739       // This should always fail:
0740       static_assert(sizeof(Other) == INT_MAX, "You can not use operator>>= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0741       return *this;
0742    }
0743 
0744    BOOST_MP_CXX14_CONSTEXPR const Arg1& value() const noexcept
0745    {
0746       return arg;
0747    }
0748 
0749    static constexpr unsigned depth = 0;
0750 
0751    template <class T
0752 #ifndef __SUNPRO_CC
0753              ,
0754              typename std::enable_if<!is_number<T>::value && !std::is_convertible<result_type, T const&>::value && std::is_constructible<T, result_type>::value, int>::type = 0
0755 #endif
0756              >
0757    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
0758    {
0759       return static_cast<T>(static_cast<result_type>(*this));
0760    }
0761    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
0762    {
0763       result_type r(*this);
0764       return static_cast<bool>(r);
0765    }
0766 
0767    template <class T>
0768    BOOST_MP_CXX14_CONSTEXPR T convert_to()
0769    {
0770       result_type r(*this);
0771       return r.template convert_to<T>();
0772    }
0773 
0774  private:
0775    typename expression_storage<Arg1>::type arg;
0776    expression&                             operator=(const expression&);
0777 };
0778 
0779 template <class tag, class Arg1, class Arg2>
0780 struct expression<tag, Arg1, Arg2, void, void>
0781 {
0782    using arity = std::integral_constant<int, 2>                                                          ;
0783    using left_type = typename arg_type<Arg1>::type                                         ;
0784    using right_type = typename arg_type<Arg2>::type                                         ;
0785    using left_result_type = typename left_type::result_type                                       ;
0786    using right_result_type = typename right_type::result_type                                      ;
0787    using result_type = typename combine_expression<left_result_type, right_result_type>::type;
0788    using tag_type = tag                                                                   ;
0789 
0790    BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a1, const Arg2& a2) : arg1(a1), arg2(a2) {}
0791    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg1(e.arg1), arg2(e.arg2) {}
0792 
0793    //
0794    // If we have static_assert we can give a more useful error message
0795    // than if we simply have no operator defined at all:
0796    //
0797    template <class Other>
0798    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
0799    {
0800       // This should always fail:
0801       static_assert(sizeof(Other) == INT_MAX, "You can not assign to a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0802       return *this;
0803    }
0804    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
0805    {
0806       // This should always fail:
0807       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0808       return *this;
0809    }
0810    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
0811    {
0812       // This should always fail:
0813       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0814       return *this;
0815    }
0816    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
0817    {
0818       // This should always fail:
0819       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0820       return *this;
0821    }
0822    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
0823    {
0824       // This should always fail:
0825       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0826       return *this;
0827    }
0828    template <class Other>
0829    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
0830    {
0831       // This should always fail:
0832       static_assert(sizeof(Other) == INT_MAX, "You can not use operator+= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0833       return *this;
0834    }
0835    template <class Other>
0836    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
0837    {
0838       // This should always fail:
0839       static_assert(sizeof(Other) == INT_MAX, "You can not use operator-= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0840       return *this;
0841    }
0842    template <class Other>
0843    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
0844    {
0845       // This should always fail:
0846       static_assert(sizeof(Other) == INT_MAX, "You can not use operator*= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0847       return *this;
0848    }
0849    template <class Other>
0850    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
0851    {
0852       // This should always fail:
0853       static_assert(sizeof(Other) == INT_MAX, "You can not use operator/= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0854       return *this;
0855    }
0856    template <class Other>
0857    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
0858    {
0859       // This should always fail:
0860       static_assert(sizeof(Other) == INT_MAX, "You can not use operator%= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0861       return *this;
0862    }
0863    template <class Other>
0864    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
0865    {
0866       // This should always fail:
0867       static_assert(sizeof(Other) == INT_MAX, "You can not use operator|= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0868       return *this;
0869    }
0870    template <class Other>
0871    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
0872    {
0873       // This should always fail:
0874       static_assert(sizeof(Other) == INT_MAX, "You can not use operator&= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0875       return *this;
0876    }
0877    template <class Other>
0878    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
0879    {
0880       // This should always fail:
0881       static_assert(sizeof(Other) == INT_MAX, "You can not use operator^= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0882       return *this;
0883    }
0884    template <class Other>
0885    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
0886    {
0887       // This should always fail:
0888       static_assert(sizeof(Other) == INT_MAX, "You can not use operator<<= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0889       return *this;
0890    }
0891    template <class Other>
0892    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
0893    {
0894       // This should always fail:
0895       static_assert(sizeof(Other) == INT_MAX, "You can not use operator>>= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0896       return *this;
0897    }
0898 
0899    BOOST_MP_CXX14_CONSTEXPR left_type left() const
0900    {
0901       return left_type(arg1);
0902    }
0903    BOOST_MP_CXX14_CONSTEXPR right_type  right() const { return right_type(arg2); }
0904    BOOST_MP_CXX14_CONSTEXPR const Arg1& left_ref() const noexcept { return arg1; }
0905    BOOST_MP_CXX14_CONSTEXPR const Arg2& right_ref() const noexcept { return arg2; }
0906 
0907    template <class T
0908 #ifndef __SUNPRO_CC
0909              ,
0910              typename std::enable_if<!is_number<T>::value && !std::is_convertible<result_type, T const&>::value && std::is_constructible<T, result_type>::value, int>::type = 0
0911 #endif
0912              >
0913    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
0914    {
0915       return static_cast<T>(static_cast<result_type>(*this));
0916    }
0917    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
0918    {
0919       result_type r(*this);
0920       return static_cast<bool>(r);
0921    }
0922    template <class T>
0923    BOOST_MP_CXX14_CONSTEXPR T convert_to()
0924    {
0925       result_type r(*this);
0926       return r.template convert_to<T>();
0927    }
0928 
0929    static const constexpr unsigned                left_depth  = left_type::depth + 1;
0930    static const constexpr unsigned                right_depth = right_type::depth + 1;
0931    static const constexpr unsigned                depth       = left_depth > right_depth ? left_depth : right_depth;
0932 
0933  private:
0934    typename expression_storage<Arg1>::type arg1;
0935    typename expression_storage<Arg2>::type arg2;
0936    expression&                             operator=(const expression&);
0937 };
0938 
0939 template <class tag, class Arg1, class Arg2, class Arg3>
0940 struct expression<tag, Arg1, Arg2, Arg3, void>
0941 {
0942    using arity = std::integral_constant<int, 3>                     ;
0943    using left_type = typename arg_type<Arg1>::type    ;
0944    using middle_type = typename arg_type<Arg2>::type    ;
0945    using right_type = typename arg_type<Arg3>::type    ;
0946    using left_result_type = typename left_type::result_type  ;
0947    using middle_result_type = typename middle_type::result_type;
0948    using right_result_type = typename right_type::result_type ;
0949    using result_type = typename combine_expression<
0950        left_result_type,
0951        typename combine_expression<right_result_type, middle_result_type>::type>::type;
0952    using tag_type = tag                                                                        ;
0953 
0954    BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a1, const Arg2& a2, const Arg3& a3) : arg1(a1), arg2(a2), arg3(a3) {}
0955    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg1(e.arg1), arg2(e.arg2), arg3(e.arg3) {}
0956 
0957    //
0958    // If we have static_assert we can give a more useful error message
0959    // than if we simply have no operator defined at all:
0960    //
0961    template <class Other>
0962    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
0963    {
0964       // This should always fail:
0965       static_assert(sizeof(Other) == INT_MAX, "You can not assign to a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0966       return *this;
0967    }
0968    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
0969    {
0970       // This should always fail:
0971       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0972       return *this;
0973    }
0974    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
0975    {
0976       // This should always fail:
0977       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0978       return *this;
0979    }
0980    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
0981    {
0982       // This should always fail:
0983       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0984       return *this;
0985    }
0986    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
0987    {
0988       // This should always fail:
0989       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0990       return *this;
0991    }
0992    template <class Other>
0993    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
0994    {
0995       // This should always fail:
0996       static_assert(sizeof(Other) == INT_MAX, "You can not use operator+= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
0997       return *this;
0998    }
0999    template <class Other>
1000    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
1001    {
1002       // This should always fail:
1003       static_assert(sizeof(Other) == INT_MAX, "You can not use operator-= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1004       return *this;
1005    }
1006    template <class Other>
1007    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
1008    {
1009       // This should always fail:
1010       static_assert(sizeof(Other) == INT_MAX, "You can not use operator*= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1011       return *this;
1012    }
1013    template <class Other>
1014    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
1015    {
1016       // This should always fail:
1017       static_assert(sizeof(Other) == INT_MAX, "You can not use operator/= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1018       return *this;
1019    }
1020    template <class Other>
1021    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
1022    {
1023       // This should always fail:
1024       static_assert(sizeof(Other) == INT_MAX, "You can not use operator%= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1025       return *this;
1026    }
1027    template <class Other>
1028    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
1029    {
1030       // This should always fail:
1031       static_assert(sizeof(Other) == INT_MAX, "You can not use operator|= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1032       return *this;
1033    }
1034    template <class Other>
1035    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
1036    {
1037       // This should always fail:
1038       static_assert(sizeof(Other) == INT_MAX, "You can not use operator&= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1039       return *this;
1040    }
1041    template <class Other>
1042    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
1043    {
1044       // This should always fail:
1045       static_assert(sizeof(Other) == INT_MAX, "You can not use operator^= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1046       return *this;
1047    }
1048    template <class Other>
1049    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
1050    {
1051       // This should always fail:
1052       static_assert(sizeof(Other) == INT_MAX, "You can not use operator<<= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1053       return *this;
1054    }
1055    template <class Other>
1056    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
1057    {
1058       // This should always fail:
1059       static_assert(sizeof(Other) == INT_MAX, "You can not use operator>>= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1060       return *this;
1061    }
1062 
1063    BOOST_MP_CXX14_CONSTEXPR left_type left() const
1064    {
1065       return left_type(arg1);
1066    }
1067    BOOST_MP_CXX14_CONSTEXPR middle_type middle() const { return middle_type(arg2); }
1068    BOOST_MP_CXX14_CONSTEXPR right_type  right() const { return right_type(arg3); }
1069    BOOST_MP_CXX14_CONSTEXPR const Arg1& left_ref() const noexcept { return arg1; }
1070    BOOST_MP_CXX14_CONSTEXPR const Arg2& middle_ref() const noexcept { return arg2; }
1071    BOOST_MP_CXX14_CONSTEXPR const Arg3& right_ref() const noexcept { return arg3; }
1072 
1073    template <class T
1074 #ifndef __SUNPRO_CC
1075              ,
1076              typename std::enable_if<!is_number<T>::value && !std::is_convertible<result_type, T const&>::value && std::is_constructible<T, result_type>::value, int>::type = 0
1077 #endif
1078              >
1079    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
1080    {
1081       return static_cast<T>(static_cast<result_type>(*this));
1082    }
1083    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
1084    {
1085       result_type r(*this);
1086       return static_cast<bool>(r);
1087    }
1088    template <class T>
1089    BOOST_MP_CXX14_CONSTEXPR T convert_to()
1090    {
1091       result_type r(*this);
1092       return r.template convert_to<T>();
1093    }
1094 
1095    static constexpr unsigned left_depth   = left_type::depth + 1;
1096    static constexpr unsigned middle_depth = middle_type::depth + 1;
1097    static constexpr unsigned right_depth  = right_type::depth + 1;
1098    static constexpr unsigned depth        = left_depth > right_depth ? (left_depth > middle_depth ? left_depth : middle_depth) : (right_depth > middle_depth ? right_depth : middle_depth);
1099 
1100  private:
1101    typename expression_storage<Arg1>::type arg1;
1102    typename expression_storage<Arg2>::type arg2;
1103    typename expression_storage<Arg3>::type arg3;
1104    expression&                             operator=(const expression&);
1105 };
1106 
1107 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1108 struct expression
1109 {
1110    using arity = std::integral_constant<int, 4>                           ;
1111    using left_type = typename arg_type<Arg1>::type          ;
1112    using left_middle_type = typename arg_type<Arg2>::type          ;
1113    using right_middle_type = typename arg_type<Arg3>::type          ;
1114    using right_type = typename arg_type<Arg4>::type          ;
1115    using left_result_type = typename left_type::result_type        ;
1116    using left_middle_result_type = typename left_middle_type::result_type ;
1117    using right_middle_result_type = typename right_middle_type::result_type;
1118    using right_result_type = typename right_type::result_type       ;
1119    using result_type = typename combine_expression<
1120        left_result_type,
1121        typename combine_expression<
1122            left_middle_result_type,
1123            typename combine_expression<right_middle_result_type, right_result_type>::type>::type>::type;
1124    using tag_type = tag                                                                                         ;
1125 
1126    BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a1, const Arg2& a2, const Arg3& a3, const Arg4& a4) : arg1(a1), arg2(a2), arg3(a3), arg4(a4) {}
1127    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg1(e.arg1), arg2(e.arg2), arg3(e.arg3), arg4(e.arg4) {}
1128 
1129    //
1130    // If we have static_assert we can give a more useful error message
1131    // than if we simply have no operator defined at all:
1132    //
1133    template <class Other>
1134    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
1135    {
1136       // This should always fail:
1137       static_assert(sizeof(Other) == INT_MAX, "You can not assign to a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1138       return *this;
1139    }
1140    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
1141    {
1142       // This should always fail:
1143       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1144       return *this;
1145    }
1146    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
1147    {
1148       // This should always fail:
1149       static_assert(sizeof(*this) == INT_MAX, "You can not increment a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1150       return *this;
1151    }
1152    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
1153    {
1154       // This should always fail:
1155       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1156       return *this;
1157    }
1158    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
1159    {
1160       // This should always fail:
1161       static_assert(sizeof(*this) == INT_MAX, "You can not decrement a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1162       return *this;
1163    }
1164    template <class Other>
1165    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
1166    {
1167       // This should always fail:
1168       static_assert(sizeof(Other) == INT_MAX, "You can not use operator+= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1169       return *this;
1170    }
1171    template <class Other>
1172    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
1173    {
1174       // This should always fail:
1175       static_assert(sizeof(Other) == INT_MAX, "You can not use operator-= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1176       return *this;
1177    }
1178    template <class Other>
1179    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
1180    {
1181       // This should always fail:
1182       static_assert(sizeof(Other) == INT_MAX, "You can not use operator*= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1183       return *this;
1184    }
1185    template <class Other>
1186    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
1187    {
1188       // This should always fail:
1189       static_assert(sizeof(Other) == INT_MAX, "You can not use operator/= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1190       return *this;
1191    }
1192    template <class Other>
1193    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
1194    {
1195       // This should always fail:
1196       static_assert(sizeof(Other) == INT_MAX, "You can not use operator%= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1197       return *this;
1198    }
1199    template <class Other>
1200    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
1201    {
1202       // This should always fail:
1203       static_assert(sizeof(Other) == INT_MAX, "You can not use operator|= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1204       return *this;
1205    }
1206    template <class Other>
1207    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
1208    {
1209       // This should always fail:
1210       static_assert(sizeof(Other) == INT_MAX, "You can not use operator&= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1211       return *this;
1212    }
1213    template <class Other>
1214    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
1215    {
1216       // This should always fail:
1217       static_assert(sizeof(Other) == INT_MAX, "You can not use operator^= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1218       return *this;
1219    }
1220    template <class Other>
1221    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
1222    {
1223       // This should always fail:
1224       static_assert(sizeof(Other) == INT_MAX, "You can not use operator<<= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1225       return *this;
1226    }
1227    template <class Other>
1228    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
1229    {
1230       // This should always fail:
1231       static_assert(sizeof(Other) == INT_MAX, "You can not use operator>>= on a Boost.Multiprecision expression template: did you inadvertantly store an expression template in a \"auto\" variable?  Or pass an expression to a template function with deduced temnplate arguments?");
1232       return *this;
1233    }
1234 
1235    BOOST_MP_CXX14_CONSTEXPR left_type left() const
1236    {
1237       return left_type(arg1);
1238    }
1239    BOOST_MP_CXX14_CONSTEXPR left_middle_type  left_middle() const { return left_middle_type(arg2); }
1240    BOOST_MP_CXX14_CONSTEXPR right_middle_type right_middle() const { return right_middle_type(arg3); }
1241    BOOST_MP_CXX14_CONSTEXPR right_type        right() const { return right_type(arg4); }
1242    BOOST_MP_CXX14_CONSTEXPR const Arg1&       left_ref() const noexcept { return arg1; }
1243    BOOST_MP_CXX14_CONSTEXPR const Arg2&       left_middle_ref() const noexcept { return arg2; }
1244    BOOST_MP_CXX14_CONSTEXPR const Arg3&       right_middle_ref() const noexcept { return arg3; }
1245    BOOST_MP_CXX14_CONSTEXPR const Arg4&       right_ref() const noexcept { return arg4; }
1246 
1247    template <class T
1248 #ifndef __SUNPRO_CC
1249              ,
1250              typename std::enable_if<!is_number<T>::value && !std::is_convertible<result_type, T const&>::value && std::is_constructible<T, result_type>::value, int>::type = 0
1251 #endif
1252              >
1253    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
1254    {
1255       return static_cast<T>(static_cast<result_type>(*this));
1256    }
1257    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
1258    {
1259       result_type r(*this);
1260       return static_cast<bool>(r);
1261    }
1262    template <class T>
1263    BOOST_MP_CXX14_CONSTEXPR T convert_to()
1264    {
1265       result_type r(*this);
1266       return r.template convert_to<T>();
1267    }
1268 
1269    static constexpr unsigned left_depth         = left_type::depth + 1;
1270    static constexpr unsigned left_middle_depth  = left_middle_type::depth + 1;
1271    static constexpr unsigned right_middle_depth = right_middle_type::depth + 1;
1272    static constexpr unsigned right_depth        = right_type::depth + 1;
1273 
1274    static constexpr unsigned left_max_depth  = left_depth > left_middle_depth ? left_depth : left_middle_depth;
1275    static constexpr unsigned right_max_depth = right_depth > right_middle_depth ? right_depth : right_middle_depth;
1276 
1277    static constexpr unsigned depth = left_max_depth > right_max_depth ? left_max_depth : right_max_depth;
1278 
1279  private:
1280    typename expression_storage<Arg1>::type arg1;
1281    typename expression_storage<Arg2>::type arg2;
1282    typename expression_storage<Arg3>::type arg3;
1283    typename expression_storage<Arg4>::type arg4;
1284    expression&                             operator=(const expression&);
1285 };
1286 
1287 template <class T>
1288 struct digits2
1289 {
1290    static_assert(std::numeric_limits<T>::is_specialized, "numeric_limits must be specialized here");
1291    static_assert((std::numeric_limits<T>::radix == 2) || (std::numeric_limits<T>::radix == 10), "Failed radix check");
1292    // If we really have so many digits that this fails, then we're probably going to hit other problems anyway:
1293    static_assert(LONG_MAX / 1000 > (std::numeric_limits<T>::digits + 1), "Too many digits to cope with here");
1294    static constexpr long  m_value = std::numeric_limits<T>::radix == 10 ? (((std::numeric_limits<T>::digits + 1) * 1000L) / 301L) : std::numeric_limits<T>::digits;
1295    static inline constexpr long value() noexcept { return m_value; }
1296 };
1297 
1298 #ifndef BOOST_MP_MIN_EXPONENT_DIGITS
1299 #ifdef _MSC_VER
1300 #define BOOST_MP_MIN_EXPONENT_DIGITS 2
1301 #else
1302 #define BOOST_MP_MIN_EXPONENT_DIGITS 2
1303 #endif
1304 #endif
1305 
1306 template <class S>
1307 void format_float_string(S& str, std::intmax_t my_exp, std::intmax_t digits, std::ios_base::fmtflags f, bool iszero)
1308 {
1309    using size_type = typename S::size_type;
1310 
1311    bool scientific = (f & std::ios_base::scientific) == std::ios_base::scientific;
1312    bool fixed      = (f & std::ios_base::fixed) == std::ios_base::fixed;
1313    bool showpoint  = (f & std::ios_base::showpoint) == std::ios_base::showpoint;
1314    bool showpos    = (f & std::ios_base::showpos) == std::ios_base::showpos;
1315 
1316    bool neg = str.size() && (str[0] == '-');
1317 
1318    if (neg)
1319       str.erase(0, 1);
1320 
1321    if (digits == 0 && !fixed)
1322    {
1323       digits = static_cast<std::intmax_t>((std::max)(str.size(), size_type(16)));
1324    }
1325 
1326    if (iszero || str.empty() || (str.find_first_not_of('0') == S::npos))
1327    {
1328       // We will be printing zero, even though the value might not
1329       // actually be zero (it just may have been rounded to zero).
1330       str = "0";
1331       if (scientific || fixed)
1332       {
1333          if (showpoint || digits > 0) {
1334             str.append(1, '.');
1335             if (digits > 0)
1336                str.append(size_type(digits), '0');
1337          }
1338          if (scientific)
1339             str.append("e+00");
1340       }
1341       else
1342       {
1343          if (showpoint)
1344          {
1345             str.append(1, '.');
1346             if (digits > 1)
1347                str.append(size_type(digits - 1), '0');
1348          }
1349       }
1350       if (neg)
1351          str.insert(static_cast<std::string::size_type>(0), 1, '-');
1352       else if (showpos)
1353          str.insert(static_cast<std::string::size_type>(0), 1, '+');
1354       return;
1355    }
1356 
1357    if (!fixed && !scientific && !showpoint)
1358    {
1359       //
1360       // Suppress trailing zeros:
1361       //
1362       std::string::iterator pos = str.end();
1363       while (pos != str.begin() && *--pos == '0')
1364       {
1365       }
1366       if (pos != str.end())
1367          ++pos;
1368       str.erase(pos, str.end());
1369       if (str.empty())
1370          str = '0';
1371    }
1372    else if (!fixed || (my_exp >= 0))
1373    {
1374       //
1375       // Pad out the end with zero's if we need to:
1376       //
1377       std::intmax_t chars = static_cast<std::intmax_t>(str.size());
1378       chars                 = digits - chars;
1379       if (scientific)
1380          ++chars;
1381       if (chars > 0)
1382       {
1383          str.append(static_cast<std::string::size_type>(chars), '0');
1384       }
1385    }
1386 
1387    if (fixed || (!scientific && (my_exp >= -4) && (my_exp < digits)))
1388    {
1389       if (1 + my_exp > static_cast<std::intmax_t>(str.size()))
1390       {
1391          // Just pad out the end with zeros:
1392          str.append(static_cast<std::string::size_type>(1 + my_exp - static_cast<std::intmax_t>(str.size())), '0');
1393          if (showpoint || (fixed && digits > 0))
1394             str.append(".");
1395       }
1396       else if (my_exp + 1 < static_cast<std::intmax_t>(str.size()))
1397       {
1398          if (my_exp < 0)
1399          {
1400             str.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(-1 - my_exp), '0');
1401             str.insert(static_cast<std::string::size_type>(0), "0.");
1402          }
1403          else
1404          {
1405             // Insert the decimal point:
1406             str.insert(static_cast<std::string::size_type>(my_exp + 1), 1, '.');
1407          }
1408       }
1409       else if (showpoint || (fixed && digits > 0)) // we have exactly the digits we require to left of the point
1410          str += ".";
1411 
1412       if (fixed)
1413       {
1414          // We may need to add trailing zeros:
1415          auto pos = str.find('.');
1416          if (pos != str.npos) { // this test is probably redundant, but just to be safe and for clarity
1417             std::intmax_t l = static_cast<std::intmax_t>(pos + 1);
1418             l               = static_cast<std::intmax_t>(digits - (static_cast<std::intmax_t>(str.size()) - l));
1419             if (l > 0)
1420                str.append(size_type(l), '0');
1421          }
1422       }
1423    }
1424    else
1425    {
1426       BOOST_MP_USING_ABS
1427       // Scientific format:
1428       if (showpoint || (str.size() > 1))
1429          str.insert(static_cast<std::string::size_type>(1u), 1, '.');
1430       str.append(static_cast<std::string::size_type>(1u), 'e');
1431 
1432       S e;
1433 
1434       #ifndef BOOST_MP_STANDALONE
1435       e = boost::lexical_cast<S>(abs(my_exp));
1436       #else
1437       BOOST_IF_CONSTEXPR(std::is_same<S, std::string>::value)
1438       {
1439          e = std::to_string(abs(my_exp));
1440       }
1441       else
1442       {
1443          const std::string str_local_exp = std::to_string(abs(my_exp));
1444          e = S(str_local_exp.cbegin(), str_local_exp.cend());
1445       }
1446       #endif
1447 
1448       if (e.size() < BOOST_MP_MIN_EXPONENT_DIGITS)
1449          e.insert(static_cast<std::string::size_type>(0), BOOST_MP_MIN_EXPONENT_DIGITS - e.size(), '0');
1450       if (my_exp < 0)
1451          e.insert(static_cast<std::string::size_type>(0), 1, '-');
1452       else
1453          e.insert(static_cast<std::string::size_type>(0), 1, '+');
1454       str.append(e);
1455    }
1456    if (neg)
1457       str.insert(static_cast<std::string::size_type>(0), 1, '-');
1458    else if (showpos)
1459       str.insert(static_cast<std::string::size_type>(0), 1, '+');
1460 }
1461 
1462 template <class V>
1463 BOOST_MP_CXX14_CONSTEXPR void check_shift_range(V val, const std::integral_constant<bool, true>&, const std::integral_constant<bool, true>&)
1464 {
1465    if (val > (std::numeric_limits<std::size_t>::max)())
1466       BOOST_MP_THROW_EXCEPTION(std::out_of_range("Can not shift by a value greater than std::numeric_limits<std::size_t>::max()."));
1467    if (val < 0)
1468       BOOST_MP_THROW_EXCEPTION(std::out_of_range("Can not shift by a negative value."));
1469 }
1470 template <class V>
1471 BOOST_MP_CXX14_CONSTEXPR void check_shift_range(V val, const std::integral_constant<bool, false>&, const std::integral_constant<bool, true>&)
1472 {
1473    if (val < 0)
1474       BOOST_MP_THROW_EXCEPTION(std::out_of_range("Can not shift by a negative value."));
1475 }
1476 template <class V>
1477 BOOST_MP_CXX14_CONSTEXPR void check_shift_range(V val, const std::integral_constant<bool, true>&, const std::integral_constant<bool, false>&)
1478 {
1479    if (val > (std::numeric_limits<std::size_t>::max)())
1480       BOOST_MP_THROW_EXCEPTION(std::out_of_range("Can not shift by a value greater than std::numeric_limits<std::size_t>::max()."));
1481 }
1482 template <class V>
1483 BOOST_MP_CXX14_CONSTEXPR void check_shift_range(V, const std::integral_constant<bool, false>&, const std::integral_constant<bool, false>&) noexcept {}
1484 
1485 template <class T>
1486 BOOST_MP_CXX14_CONSTEXPR const T& evaluate_if_expression(const T& val) { return val; }
1487 template <class T>
1488 BOOST_MP_CXX14_CONSTEXPR T&& evaluate_if_expression(T&& val) { return static_cast<T&&>(val); }
1489 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1490 BOOST_MP_CXX14_CONSTEXPR typename expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type evaluate_if_expression(const expression<tag, Arg1, Arg2, Arg3, Arg4>& val) { return val; }
1491 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1492 BOOST_MP_CXX14_CONSTEXPR typename expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type evaluate_if_expression(expression<tag, Arg1, Arg2, Arg3, Arg4>&& val) { return val; }
1493 
1494 template <class T>
1495 struct convertible_to
1496 {
1497    operator T () const;
1498 };
1499 
1500 } // namespace detail
1501 
1502 //
1503 // Traits class, lets us know what kind of number we have, defaults to a floating point type:
1504 //
1505 enum number_category_type
1506 {
1507    number_kind_unknown        = -1,
1508    number_kind_integer        = 0,
1509    number_kind_floating_point = 1,
1510    number_kind_rational       = 2,
1511    number_kind_fixed_point    = 3,
1512    number_kind_complex        = 4
1513 };
1514 
1515 template <class Num, bool, bool>
1516 struct number_category_base : public std::integral_constant<int, number_kind_unknown>
1517 {};
1518 template <class Num>
1519 struct number_category_base<Num, true, false> : public std::integral_constant<int, std::numeric_limits<Num>::is_integer ? number_kind_integer : (std::numeric_limits<Num>::max_exponent ? number_kind_floating_point : number_kind_unknown)>
1520 {};
1521 template <class Num>
1522 struct number_category : public number_category_base<Num, std::is_class<Num>::value || boost::multiprecision::detail::is_arithmetic<Num>::value, std::is_abstract<Num>::value>
1523 {};
1524 template <class Backend, expression_template_option ExpressionTemplates>
1525 struct number_category<number<Backend, ExpressionTemplates> > : public number_category<Backend>
1526 {};
1527 template <class tag, class A1, class A2, class A3, class A4>
1528 struct number_category<detail::expression<tag, A1, A2, A3, A4> > : public number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>
1529 {};
1530 //
1531 // Specializations for types which do not always have numberic_limits specializations:
1532 //
1533 #ifdef BOOST_HAS_INT128
1534 template <>
1535 struct number_category<boost::multiprecision::int128_type> : public std::integral_constant<int, number_kind_integer>
1536 {};
1537 template <>
1538 struct number_category<boost::multiprecision::uint128_type> : public std::integral_constant<int, number_kind_integer>
1539 {};
1540 #endif
1541 #ifdef BOOST_HAS_FLOAT128
1542 template <>
1543 struct number_category<boost::multiprecision::float128_type> : public std::integral_constant<int, number_kind_floating_point>
1544 {};
1545 #endif
1546 
1547 template <class T>
1548 struct component_type
1549 {
1550    using type = T;
1551 };
1552 template <class tag, class A1, class A2, class A3, class A4>
1553 struct component_type<detail::expression<tag, A1, A2, A3, A4> > : public component_type<typename detail::expression<tag, A1, A2, A3, A4>::result_type>
1554 {};
1555 
1556 template <class T>
1557 struct scalar_result_from_possible_complex
1558 {
1559    using type = typename std::conditional<number_category<T>::value == number_kind_complex, typename component_type<T>::type, T>::type;
1560 };
1561 
1562 template <class T>
1563 struct complex_result_from_scalar; // individual backends must specialize this trait.
1564 
1565 template <class T>
1566 struct is_unsigned_number : public std::integral_constant<bool, false>
1567 {};
1568 template <class Backend, expression_template_option ExpressionTemplates>
1569 struct is_unsigned_number<number<Backend, ExpressionTemplates> > : public is_unsigned_number<Backend>
1570 {};
1571 template <class T>
1572 struct is_signed_number : public std::integral_constant<bool, !is_unsigned_number<T>::value>
1573 {};
1574 template <class T>
1575 struct is_interval_number : public std::integral_constant<bool, false>
1576 {};
1577 template <class Backend, expression_template_option ExpressionTemplates>
1578 struct is_interval_number<number<Backend, ExpressionTemplates> > : public is_interval_number<Backend>
1579 {};
1580 
1581 template <class T, class U>
1582 struct is_equivalent_number_type : public std::is_same<T, U>
1583 {};
1584 
1585 template <class Backend, expression_template_option ExpressionTemplates, class T2>
1586 struct is_equivalent_number_type<number<Backend, ExpressionTemplates>, T2> : public is_equivalent_number_type<Backend, T2>
1587 {};
1588 template <class T1, class Backend, expression_template_option ExpressionTemplates>
1589 struct is_equivalent_number_type<T1, number<Backend, ExpressionTemplates> > : public is_equivalent_number_type<Backend, T1>
1590 {};
1591 template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2>
1592 struct is_equivalent_number_type<number<Backend, ExpressionTemplates>, number<Backend2, ExpressionTemplates2> > : public is_equivalent_number_type<Backend, Backend2>
1593 {};
1594 
1595 }
1596 } // namespace boost
1597 
1598 #ifdef BOOST_MP_MATH_AVAILABLE
1599 namespace boost { namespace math {
1600    namespace tools {
1601 
1602       template <class T>
1603       struct promote_arg;
1604 
1605       template <class tag, class A1, class A2, class A3, class A4>
1606       struct promote_arg<boost::multiprecision::detail::expression<tag, A1, A2, A3, A4> >
1607       {
1608          using type = typename boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
1609       };
1610 
1611       template <class R, class B, boost::multiprecision::expression_template_option ET>
1612       inline R real_cast(const boost::multiprecision::number<B, ET>& val)
1613       {
1614          return val.template convert_to<R>();
1615       }
1616 
1617       template <class R, class tag, class A1, class A2, class A3, class A4>
1618       inline R real_cast(const boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>& val)
1619       {
1620          using val_type = typename boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
1621          return val_type(val).template convert_to<R>();
1622       }
1623 
1624       template <class B, boost::multiprecision::expression_template_option ET>
1625       struct is_complex_type<boost::multiprecision::number<B, ET> > : public std::integral_constant<bool, boost::multiprecision::number_category<B>::value == boost::multiprecision::number_kind_complex> {};
1626 
1627 } // namespace tools
1628 
1629 namespace constants {
1630 
1631 template <class T>
1632 struct is_explicitly_convertible_from_string;
1633 
1634 template <class B, boost::multiprecision::expression_template_option ET>
1635 struct is_explicitly_convertible_from_string<boost::multiprecision::number<B, ET> >
1636 {
1637    static constexpr bool value = true;
1638 };
1639 
1640 } // namespace constants
1641 
1642 }} // namespace boost::math
1643 #endif
1644 
1645 #ifdef BOOST_MSVC
1646 #pragma warning(pop)
1647 #endif
1648 
1649 #endif // BOOST_MP_NUMBER_BASE_HPP