Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / multiprecision / detail / number_base.hpp
1 ///////////////////////////////////////////////////////////////////////////////
2 //  Copyright 2011 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #ifndef BOOST_MATH_BIG_NUM_BASE_HPP
7 #define BOOST_MATH_BIG_NUM_BASE_HPP
8
9 #include <limits>
10 #include <boost/utility/enable_if.hpp>
11 #include <boost/core/nvp.hpp>
12 #include <boost/type_traits/is_convertible.hpp>
13 #include <boost/type_traits/is_constructible.hpp>
14 #include <boost/type_traits/decay.hpp>
15 #include <boost/math/tools/complex.hpp>
16 #ifdef BOOST_MSVC
17 #pragma warning(push)
18 #pragma warning(disable : 4307)
19 #endif
20 #include <boost/lexical_cast.hpp>
21 #ifdef BOOST_MSVC
22 #pragma warning(pop)
23 #endif
24
25 #if defined(NDEBUG) && !defined(_DEBUG)
26 #define BOOST_MP_FORCEINLINE BOOST_FORCEINLINE
27 #else
28 #define BOOST_MP_FORCEINLINE inline
29 #endif
30
31 #if (defined(BOOST_GCC) && (BOOST_GCC <= 40700)) || BOOST_WORKAROUND(__SUNPRO_CC, < 0x5140) || (defined(__clang_major__) && (__clang_major__ == 3) && (__clang_minor__ < 5))
32 #define BOOST_MP_NOEXCEPT_IF(x)
33 #else
34 #define BOOST_MP_NOEXCEPT_IF(x) BOOST_NOEXCEPT_IF(x)
35 #endif
36
37 #if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) || BOOST_WORKAROUND(__SUNPRO_CC, < 0x5140)
38 #define BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
39 #endif
40
41 //
42 // Thread local storage:
43 // Note fails on Mingw, see https://sourceforge.net/p/mingw-w64/bugs/527/
44 //
45 #if !defined(BOOST_NO_CXX11_THREAD_LOCAL) && !defined(BOOST_INTEL) && !defined(__MINGW32__)
46 #define BOOST_MP_THREAD_LOCAL thread_local
47 #define BOOST_MP_USING_THREAD_LOCAL
48 #else
49 #define BOOST_MP_THREAD_LOCAL
50 #endif
51
52 #ifdef __has_include
53 # if __has_include(<version>)
54 #  include <version>
55 #  ifdef __cpp_lib_is_constant_evaluated
56 #   include <type_traits>
57 #   define BOOST_MP_HAS_IS_CONSTANT_EVALUATED
58 #  endif
59 # endif
60 #endif
61
62 #ifdef __has_builtin
63 #if __has_builtin(__builtin_is_constant_evaluated) && !defined(BOOST_NO_CXX14_CONSTEXPR) && !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX)
64 #define BOOST_MP_CLANG_CD
65 #endif
66 #endif
67
68 #if defined(BOOST_MP_HAS_IS_CONSTANT_EVALUATED) && !defined(BOOST_NO_CXX14_CONSTEXPR)
69 #  define BOOST_MP_IS_CONST_EVALUATED(x) std::is_constant_evaluated()
70 #elif (defined(BOOST_GCC) && !defined(BOOST_NO_CXX14_CONSTEXPR) && (__GNUC__ >= 9)) || defined(BOOST_MP_CLANG_CD)
71 #  define BOOST_MP_IS_CONST_EVALUATED(x) __builtin_is_constant_evaluated()
72 #elif !defined(BOOST_NO_CXX14_CONSTEXPR) && defined(BOOST_GCC) && (__GNUC__ >= 6)
73 #  define BOOST_MP_IS_CONST_EVALUATED(x) __builtin_constant_p(x)
74 #else
75 #  define BOOST_MP_NO_CONSTEXPR_DETECTION
76 #endif
77
78 #define BOOST_MP_CXX14_CONSTEXPR BOOST_CXX14_CONSTEXPR
79 //
80 // Early compiler versions trip over the constexpr code:
81 //
82 #if defined(__clang__) && (__clang_major__ < 5)
83 #undef BOOST_MP_CXX14_CONSTEXPR
84 #define BOOST_MP_CXX14_CONSTEXPR
85 #endif
86 #if defined(__apple_build_version__) && (__clang_major__ < 9)
87 #undef BOOST_MP_CXX14_CONSTEXPR
88 #define BOOST_MP_CXX14_CONSTEXPR
89 #endif
90 #if defined(BOOST_GCC) && (__GNUC__ < 6)
91 #undef BOOST_MP_CXX14_CONSTEXPR
92 #define BOOST_MP_CXX14_CONSTEXPR
93 #endif
94
95 #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
96 #  define BOOST_CXX14_CONSTEXPR_IF_DETECTION
97 #else
98 #  define BOOST_CXX14_CONSTEXPR_IF_DETECTION constexpr
99 #endif
100
101 #ifdef BOOST_MSVC
102 #pragma warning(push)
103 #pragma warning(disable : 6326)
104 #endif
105
106 namespace boost {
107 namespace multiprecision {
108
109 enum expression_template_option
110 {
111    et_off = 0,
112    et_on  = 1
113 };
114
115 template <class Backend>
116 struct expression_template_default
117 {
118    static const expression_template_option value = et_on;
119 };
120
121 template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
122 class number;
123
124 template <class T>
125 struct is_number : public mpl::false_
126 {};
127
128 template <class Backend, expression_template_option ExpressionTemplates>
129 struct is_number<number<Backend, ExpressionTemplates> > : public mpl::true_
130 {};
131
132 template <class T>
133 struct is_et_number : public mpl::false_
134 {};
135
136 template <class Backend>
137 struct is_et_number<number<Backend, et_on> > : public mpl::true_
138 {};
139
140 template <class T>
141 struct is_no_et_number : public mpl::false_
142 {};
143
144 template <class Backend>
145 struct is_no_et_number<number<Backend, et_off> > : public mpl::true_
146 {};
147
148 namespace detail {
149
150 // Forward-declare an expression wrapper
151 template <class tag, class Arg1 = void, class Arg2 = void, class Arg3 = void, class Arg4 = void>
152 struct expression;
153
154 } // namespace detail
155
156 template <class T>
157 struct is_number_expression : public mpl::false_
158 {};
159
160 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
161 struct is_number_expression<detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > : public mpl::true_
162 {};
163
164 template <class T, class Num>
165 struct is_compatible_arithmetic_type
166     : public mpl::bool_<
167           is_convertible<T, Num>::value && !is_same<T, Num>::value && !is_number_expression<T>::value>
168 {};
169
170 namespace detail {
171 //
172 // Workaround for missing abs(boost::long_long_type) and abs(__int128) on some compilers:
173 //
174 template <class T>
175 BOOST_CONSTEXPR typename enable_if_c<(is_signed<T>::value || is_floating_point<T>::value), T>::type abs(T t) BOOST_NOEXCEPT
176 {
177    // This strange expression avoids a hardware trap in the corner case
178    // that val is the most negative value permitted in boost::long_long_type.
179    // See https://svn.boost.org/trac/boost/ticket/9740.
180    return t < 0 ? T(1u) + T(-(t + 1)) : t;
181 }
182 template <class T>
183 BOOST_CONSTEXPR typename enable_if_c<(is_unsigned<T>::value), T>::type abs(T t) BOOST_NOEXCEPT
184 {
185    return t;
186 }
187
188 #define BOOST_MP_USING_ABS using boost::multiprecision::detail::abs;
189
190 template <class T>
191 BOOST_CONSTEXPR typename enable_if_c<(is_signed<T>::value || is_floating_point<T>::value), typename make_unsigned<T>::type>::type unsigned_abs(T t) BOOST_NOEXCEPT
192 {
193    // This strange expression avoids a hardware trap in the corner case
194    // that val is the most negative value permitted in boost::long_long_type.
195    // See https://svn.boost.org/trac/boost/ticket/9740.
196    return t < 0 ? static_cast<typename make_unsigned<T>::type>(1u) + static_cast<typename make_unsigned<T>::type>(-(t + 1)) : static_cast<typename make_unsigned<T>::type>(t);
197 }
198 template <class T>
199 BOOST_CONSTEXPR typename enable_if_c<(is_unsigned<T>::value), T>::type unsigned_abs(T t) BOOST_NOEXCEPT
200 {
201    return t;
202 }
203
204 //
205 // Move support:
206 //
207 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
208 #define BOOST_MP_MOVE(x) std::move(x)
209 #else
210 #define BOOST_MP_MOVE(x) x
211 #endif
212
213 template <class T>
214 struct bits_of
215 {
216    BOOST_STATIC_ASSERT(is_integral<T>::value || is_enum<T>::value || std::numeric_limits<T>::is_specialized);
217    static const unsigned value =
218        std::numeric_limits<T>::is_specialized ? std::numeric_limits<T>::digits
219                                               : sizeof(T) * CHAR_BIT - (is_signed<T>::value ? 1 : 0);
220 };
221
222 #if defined(_GLIBCXX_USE_FLOAT128) && defined(BOOST_GCC) && !defined(__STRICT_ANSI__)
223 template <>
224 struct bits_of<__float128>
225 {
226    static const unsigned value = 113;
227 };
228 #endif
229
230 template <int b>
231 struct has_enough_bits
232 {
233    template <class T>
234    struct type : public mpl::bool_<bits_of<T>::value >= b>
235    {};
236 };
237
238 template <class Val, class Backend, class Tag>
239 struct canonical_imp
240 {
241    typedef typename remove_cv<typename decay<const Val>::type>::type type;
242 };
243 template <class B, class Backend, class Tag>
244 struct canonical_imp<number<B, et_on>, Backend, Tag>
245 {
246    typedef B type;
247 };
248 template <class B, class Backend, class Tag>
249 struct canonical_imp<number<B, et_off>, Backend, Tag>
250 {
251    typedef B type;
252 };
253 #ifdef __SUNPRO_CC
254 template <class B, class Backend>
255 struct canonical_imp<number<B, et_on>, Backend, mpl::int_<3> >
256 {
257    typedef B type;
258 };
259 template <class B, class Backend>
260 struct canonical_imp<number<B, et_off>, Backend, mpl::int_<3> >
261 {
262    typedef B type;
263 };
264 #endif
265 template <class Val, class Backend>
266 struct canonical_imp<Val, Backend, mpl::int_<0> >
267 {
268    typedef typename has_enough_bits<bits_of<Val>::value>::template type<mpl::_> pred_type;
269    typedef typename mpl::find_if<
270        typename Backend::signed_types,
271        pred_type>::type                                                                                                 iter_type;
272    typedef typename mpl::end<typename Backend::signed_types>::type                                                      end_type;
273    typedef typename mpl::eval_if<boost::is_same<iter_type, end_type>, mpl::identity<Val>, mpl::deref<iter_type> >::type type;
274 };
275 template <class Val, class Backend>
276 struct canonical_imp<Val, Backend, mpl::int_<1> >
277 {
278    typedef typename has_enough_bits<bits_of<Val>::value>::template type<mpl::_> pred_type;
279    typedef typename mpl::find_if<
280        typename Backend::unsigned_types,
281        pred_type>::type                                                                                                 iter_type;
282    typedef typename mpl::end<typename Backend::unsigned_types>::type                                                    end_type;
283    typedef typename mpl::eval_if<boost::is_same<iter_type, end_type>, mpl::identity<Val>, mpl::deref<iter_type> >::type type;
284 };
285 template <class Val, class Backend>
286 struct canonical_imp<Val, Backend, mpl::int_<2> >
287 {
288    typedef typename has_enough_bits<bits_of<Val>::value>::template type<mpl::_> pred_type;
289    typedef typename mpl::find_if<
290        typename Backend::float_types,
291        pred_type>::type                                                                                                 iter_type;
292    typedef typename mpl::end<typename Backend::float_types>::type                                                       end_type;
293    typedef typename mpl::eval_if<boost::is_same<iter_type, end_type>, mpl::identity<Val>, mpl::deref<iter_type> >::type type;
294 };
295 template <class Val, class Backend>
296 struct canonical_imp<Val, Backend, mpl::int_<3> >
297 {
298    typedef const char* type;
299 };
300
301 template <class Val, class Backend>
302 struct canonical
303 {
304    typedef typename mpl::if_<
305        is_signed<Val>,
306        mpl::int_<0>,
307        typename mpl::if_<
308            is_unsigned<Val>,
309            mpl::int_<1>,
310            typename mpl::if_<
311                is_floating_point<Val>,
312                mpl::int_<2>,
313                typename mpl::if_<
314                    mpl::or_<
315                        is_convertible<Val, const char*>,
316                        is_same<Val, std::string> >,
317                    mpl::int_<3>,
318                    mpl::int_<4> >::type>::type>::type>::type tag_type;
319
320    typedef typename canonical_imp<Val, Backend, tag_type>::type type;
321 };
322
323 struct terminal
324 {};
325 struct negate
326 {};
327 struct plus
328 {};
329 struct minus
330 {};
331 struct multiplies
332 {};
333 struct divides
334 {};
335 struct modulus
336 {};
337 struct shift_left
338 {};
339 struct shift_right
340 {};
341 struct bitwise_and
342 {};
343 struct bitwise_or
344 {};
345 struct bitwise_xor
346 {};
347 struct bitwise_complement
348 {};
349 struct add_immediates
350 {};
351 struct subtract_immediates
352 {};
353 struct multiply_immediates
354 {};
355 struct divide_immediates
356 {};
357 struct modulus_immediates
358 {};
359 struct bitwise_and_immediates
360 {};
361 struct bitwise_or_immediates
362 {};
363 struct bitwise_xor_immediates
364 {};
365 struct complement_immediates
366 {};
367 struct function
368 {};
369 struct multiply_add
370 {};
371 struct multiply_subtract
372 {};
373
374 template <class T>
375 struct backend_type;
376
377 template <class T, expression_template_option ExpressionTemplates>
378 struct backend_type<number<T, ExpressionTemplates> >
379 {
380    typedef T type;
381 };
382
383 template <class tag, class A1, class A2, class A3, class A4>
384 struct backend_type<expression<tag, A1, A2, A3, A4> >
385 {
386    typedef typename backend_type<typename expression<tag, A1, A2, A3, A4>::result_type>::type type;
387 };
388
389 template <class T1, class T2>
390 struct combine_expression
391 {
392 #ifdef BOOST_NO_CXX11_DECLTYPE
393    typedef typename mpl::if_c<(sizeof(T1() + T2()) == sizeof(T1)), T1, T2>::type type;
394 #else
395    typedef decltype(T1() + T2()) type;
396 #endif
397 };
398
399 template <class T1, expression_template_option ExpressionTemplates, class T2>
400 struct combine_expression<number<T1, ExpressionTemplates>, T2>
401 {
402    typedef number<T1, ExpressionTemplates> type;
403 };
404
405 template <class T1, class T2, expression_template_option ExpressionTemplates>
406 struct combine_expression<T1, number<T2, ExpressionTemplates> >
407 {
408    typedef number<T2, ExpressionTemplates> type;
409 };
410
411 template <class T, expression_template_option ExpressionTemplates>
412 struct combine_expression<number<T, ExpressionTemplates>, number<T, ExpressionTemplates> >
413 {
414    typedef number<T, ExpressionTemplates> type;
415 };
416
417 template <class T1, expression_template_option ExpressionTemplates1, class T2, expression_template_option ExpressionTemplates2>
418 struct combine_expression<number<T1, ExpressionTemplates1>, number<T2, ExpressionTemplates2> >
419 {
420    typedef typename mpl::if_c<
421        is_convertible<number<T2, ExpressionTemplates2>, number<T1, ExpressionTemplates2> >::value,
422        number<T1, ExpressionTemplates1>,
423        number<T2, ExpressionTemplates2> >::type type;
424 };
425
426 template <class T>
427 struct arg_type
428 {
429    typedef expression<terminal, T> type;
430 };
431
432 template <class Tag, class Arg1, class Arg2, class Arg3, class Arg4>
433 struct arg_type<expression<Tag, Arg1, Arg2, Arg3, Arg4> >
434 {
435    typedef expression<Tag, Arg1, Arg2, Arg3, Arg4> type;
436 };
437
438 struct unmentionable
439 {
440    unmentionable* proc() { return 0; }
441 };
442
443 typedef unmentionable* (unmentionable::*unmentionable_type)();
444
445 template <class T, bool b>
446 struct expression_storage_base
447 {
448    typedef const T& type;
449 };
450
451 template <class T>
452 struct expression_storage_base<T, true>
453 {
454    typedef T type;
455 };
456
457 template <class T>
458 struct expression_storage : public expression_storage_base<T, boost::is_arithmetic<T>::value>
459 {};
460
461 template <class T>
462 struct expression_storage<T*>
463 {
464    typedef T* type;
465 };
466
467 template <class T>
468 struct expression_storage<const T*>
469 {
470    typedef const T* type;
471 };
472
473 template <class tag, class A1, class A2, class A3, class A4>
474 struct expression_storage<expression<tag, A1, A2, A3, A4> >
475 {
476    typedef expression<tag, A1, A2, A3, A4> type;
477 };
478
479 template <class tag, class Arg1>
480 struct expression<tag, Arg1, void, void, void>
481 {
482    typedef mpl::int_<1>                    arity;
483    typedef typename arg_type<Arg1>::type   left_type;
484    typedef typename left_type::result_type left_result_type;
485    typedef typename left_type::result_type result_type;
486    typedef tag                             tag_type;
487
488    explicit BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a) : arg(a) {}
489    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg(e.arg) {}
490
491 #ifndef BOOST_NO_CXX11_STATIC_ASSERT
492    //
493    // If we have static_assert we can give a more useful error message
494    // than if we simply have no operator defined at all:
495    //
496    template <class Other>
497    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
498    {
499       // This should always fail:
500       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?");
501       return *this;
502    }
503    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
504    {
505       // This should always fail:
506       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?");
507       return *this;
508    }
509    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
510    {
511       // This should always fail:
512       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?");
513       return *this;
514    }
515    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
516    {
517       // This should always fail:
518       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?");
519       return *this;
520    }
521    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
522    {
523       // This should always fail:
524       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?");
525       return *this;
526    }
527    template <class Other>
528    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
529    {
530       // This should always fail:
531       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?");
532       return *this;
533    }
534    template <class Other>
535    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
536    {
537       // This should always fail:
538       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?");
539       return *this;
540    }
541    template <class Other>
542    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
543    {
544       // This should always fail:
545       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?");
546       return *this;
547    }
548    template <class Other>
549    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
550    {
551       // This should always fail:
552       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?");
553       return *this;
554    }
555    template <class Other>
556    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
557    {
558       // This should always fail:
559       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?");
560       return *this;
561    }
562    template <class Other>
563    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
564    {
565       // This should always fail:
566       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?");
567       return *this;
568    }
569    template <class Other>
570    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
571    {
572       // This should always fail:
573       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?");
574       return *this;
575    }
576    template <class Other>
577    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
578    {
579       // This should always fail:
580       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?");
581       return *this;
582    }
583    template <class Other>
584    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
585    {
586       // This should always fail:
587       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?");
588       return *this;
589    }
590    template <class Other>
591    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
592    {
593       // This should always fail:
594       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?");
595       return *this;
596    }
597 #endif
598
599    BOOST_MP_CXX14_CONSTEXPR left_type left() const
600    {
601       return left_type(arg);
602    }
603
604    BOOST_MP_CXX14_CONSTEXPR const Arg1& left_ref() const BOOST_NOEXCEPT { return arg; }
605
606    static const unsigned depth = left_type::depth + 1;
607 #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
608 #if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
609    //
610    // Horrible workaround for gcc-4.6.x which always prefers the template
611    // operator bool() rather than the non-template operator when converting to
612    // an arithmetic type:
613    //
614    template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
615    explicit operator T() const
616    {
617       result_type r(*this);
618       return static_cast<bool>(r);
619    }
620    template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
621    explicit operator T() const
622    {
623       return static_cast<T>(static_cast<result_type>(*this));
624    }
625 #else
626    template <class T
627 #ifndef __SUNPRO_CC
628              ,
629              typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value || !is_constructible<T, result_type>::value, int>::type = 0
630 #endif
631              >
632    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
633    {
634       return static_cast<T>(static_cast<result_type>(*this));
635    }
636    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
637    {
638       result_type r(*this);
639       return static_cast<bool>(r);
640    }
641 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
642    BOOST_MP_FORCEINLINE explicit operator void() const
643    {}
644 #endif
645 #endif
646 #else
647    operator unmentionable_type() const
648    {
649       result_type r(*this);
650       return r ? &unmentionable::proc : 0;
651    }
652 #endif
653
654    template <class T>
655    BOOST_MP_CXX14_CONSTEXPR T convert_to()
656    {
657       result_type r(*this);
658       return r.template convert_to<T>();
659    }
660
661  private:
662    typename expression_storage<Arg1>::type arg;
663    expression&                             operator=(const expression&);
664 };
665
666 template <class Arg1>
667 struct expression<terminal, Arg1, void, void, void>
668 {
669    typedef mpl::int_<0> arity;
670    typedef Arg1         result_type;
671    typedef terminal     tag_type;
672
673    explicit BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a) : arg(a) {}
674    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg(e.arg) {}
675
676 #ifndef BOOST_NO_CXX11_STATIC_ASSERT
677    //
678    // If we have static_assert we can give a more useful error message
679    // than if we simply have no operator defined at all:
680    //
681    template <class Other>
682    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
683    {
684       // This should always fail:
685       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?");
686       return *this;
687    }
688    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
689    {
690       // This should always fail:
691       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?");
692       return *this;
693    }
694    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
695    {
696       // This should always fail:
697       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?");
698       return *this;
699    }
700    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
701    {
702       // This should always fail:
703       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?");
704       return *this;
705    }
706    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
707    {
708       // This should always fail:
709       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?");
710       return *this;
711    }
712    template <class Other>
713    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
714    {
715       // This should always fail:
716       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?");
717       return *this;
718    }
719    template <class Other>
720    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
721    {
722       // This should always fail:
723       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?");
724       return *this;
725    }
726    template <class Other>
727    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
728    {
729       // This should always fail:
730       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?");
731       return *this;
732    }
733    template <class Other>
734    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
735    {
736       // This should always fail:
737       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?");
738       return *this;
739    }
740    template <class Other>
741    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
742    {
743       // This should always fail:
744       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?");
745       return *this;
746    }
747    template <class Other>
748    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
749    {
750       // This should always fail:
751       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?");
752       return *this;
753    }
754    template <class Other>
755    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
756    {
757       // This should always fail:
758       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?");
759       return *this;
760    }
761    template <class Other>
762    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
763    {
764       // This should always fail:
765       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?");
766       return *this;
767    }
768    template <class Other>
769    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
770    {
771       // This should always fail:
772       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?");
773       return *this;
774    }
775    template <class Other>
776    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
777    {
778       // This should always fail:
779       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?");
780       return *this;
781    }
782 #endif
783
784    BOOST_MP_CXX14_CONSTEXPR const Arg1& value() const BOOST_NOEXCEPT
785    {
786       return arg;
787    }
788
789    static const unsigned depth = 0;
790
791 #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
792 #if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
793    //
794    // Horrible workaround for gcc-4.6.x which always prefers the template
795    // operator bool() rather than the non-template operator when converting to
796    // an arithmetic type:
797    //
798    template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
799    explicit operator T() const
800    {
801       result_type r(*this);
802       return static_cast<bool>(r);
803    }
804    template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
805    explicit operator T() const
806    {
807       return static_cast<T>(static_cast<result_type>(*this));
808    }
809 #else
810    template <class T
811 #ifndef __SUNPRO_CC
812              ,
813              typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value || !is_constructible<T, result_type>::value, int>::type = 0
814 #endif
815              >
816    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
817    {
818       return static_cast<T>(static_cast<result_type>(*this));
819    }
820    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
821    {
822       result_type r(*this);
823       return static_cast<bool>(r);
824    }
825 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
826    BOOST_MP_FORCEINLINE explicit operator void() const
827    {}
828 #endif
829 #endif
830 #else
831    operator unmentionable_type() const
832    {
833       return arg ? &unmentionable::proc : 0;
834    }
835 #endif
836
837    template <class T>
838    BOOST_MP_CXX14_CONSTEXPR T convert_to()
839    {
840       result_type r(*this);
841       return r.template convert_to<T>();
842    }
843
844  private:
845    typename expression_storage<Arg1>::type arg;
846    expression&                             operator=(const expression&);
847 };
848
849 template <class tag, class Arg1, class Arg2>
850 struct expression<tag, Arg1, Arg2, void, void>
851 {
852    typedef mpl::int_<2>                                                           arity;
853    typedef typename arg_type<Arg1>::type                                          left_type;
854    typedef typename arg_type<Arg2>::type                                          right_type;
855    typedef typename left_type::result_type                                        left_result_type;
856    typedef typename right_type::result_type                                       right_result_type;
857    typedef typename combine_expression<left_result_type, right_result_type>::type result_type;
858    typedef tag                                                                    tag_type;
859
860    BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a1, const Arg2& a2) : arg1(a1), arg2(a2) {}
861    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg1(e.arg1), arg2(e.arg2) {}
862
863 #ifndef BOOST_NO_CXX11_STATIC_ASSERT
864    //
865    // If we have static_assert we can give a more useful error message
866    // than if we simply have no operator defined at all:
867    //
868    template <class Other>
869    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
870    {
871       // This should always fail:
872       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?");
873       return *this;
874    }
875    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
876    {
877       // This should always fail:
878       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?");
879       return *this;
880    }
881    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
882    {
883       // This should always fail:
884       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?");
885       return *this;
886    }
887    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
888    {
889       // This should always fail:
890       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?");
891       return *this;
892    }
893    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
894    {
895       // This should always fail:
896       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?");
897       return *this;
898    }
899    template <class Other>
900    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
901    {
902       // This should always fail:
903       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?");
904       return *this;
905    }
906    template <class Other>
907    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
908    {
909       // This should always fail:
910       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?");
911       return *this;
912    }
913    template <class Other>
914    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
915    {
916       // This should always fail:
917       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?");
918       return *this;
919    }
920    template <class Other>
921    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
922    {
923       // This should always fail:
924       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?");
925       return *this;
926    }
927    template <class Other>
928    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
929    {
930       // This should always fail:
931       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?");
932       return *this;
933    }
934    template <class Other>
935    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
936    {
937       // This should always fail:
938       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?");
939       return *this;
940    }
941    template <class Other>
942    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
943    {
944       // This should always fail:
945       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?");
946       return *this;
947    }
948    template <class Other>
949    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
950    {
951       // This should always fail:
952       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?");
953       return *this;
954    }
955    template <class Other>
956    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
957    {
958       // This should always fail:
959       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?");
960       return *this;
961    }
962    template <class Other>
963    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
964    {
965       // This should always fail:
966       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?");
967       return *this;
968    }
969 #endif
970
971    BOOST_MP_CXX14_CONSTEXPR left_type left() const
972    {
973       return left_type(arg1);
974    }
975    BOOST_MP_CXX14_CONSTEXPR right_type  right() const { return right_type(arg2); }
976    BOOST_MP_CXX14_CONSTEXPR const Arg1& left_ref() const BOOST_NOEXCEPT { return arg1; }
977    BOOST_MP_CXX14_CONSTEXPR const Arg2& right_ref() const BOOST_NOEXCEPT { return arg2; }
978
979 #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
980 #if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
981    //
982    // Horrible workaround for gcc-4.6.x which always prefers the template
983    // operator bool() rather than the non-template operator when converting to
984    // an arithmetic type:
985    //
986    template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
987    explicit operator T() const
988    {
989       result_type r(*this);
990       return static_cast<bool>(r);
991    }
992    template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
993    explicit operator T() const
994    {
995       return static_cast<T>(static_cast<result_type>(*this));
996    }
997 #else
998    template <class T
999 #ifndef __SUNPRO_CC
1000              ,
1001              typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value || !is_constructible<T, result_type>::value, int>::type = 0
1002 #endif
1003              >
1004    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
1005    {
1006       return static_cast<T>(static_cast<result_type>(*this));
1007    }
1008    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
1009    {
1010       result_type r(*this);
1011       return static_cast<bool>(r);
1012    }
1013 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
1014    BOOST_MP_FORCEINLINE explicit operator void() const
1015    {}
1016 #endif
1017 #endif
1018 #else
1019    operator unmentionable_type() const
1020    {
1021       result_type r(*this);
1022       return r ? &unmentionable::proc : 0;
1023    }
1024 #endif
1025    template <class T>
1026    BOOST_MP_CXX14_CONSTEXPR T convert_to()
1027    {
1028       result_type r(*this);
1029       return r.template convert_to<T>();
1030    }
1031
1032    static const BOOST_MP_CXX14_CONSTEXPR unsigned left_depth  = left_type::depth + 1;
1033    static const BOOST_MP_CXX14_CONSTEXPR unsigned right_depth = right_type::depth + 1;
1034    static const BOOST_MP_CXX14_CONSTEXPR unsigned depth       = left_depth > right_depth ? left_depth : right_depth;
1035
1036  private:
1037    typename expression_storage<Arg1>::type arg1;
1038    typename expression_storage<Arg2>::type arg2;
1039    expression&                             operator=(const expression&);
1040 };
1041
1042 template <class tag, class Arg1, class Arg2, class Arg3>
1043 struct expression<tag, Arg1, Arg2, Arg3, void>
1044 {
1045    typedef mpl::int_<3>                      arity;
1046    typedef typename arg_type<Arg1>::type     left_type;
1047    typedef typename arg_type<Arg2>::type     middle_type;
1048    typedef typename arg_type<Arg3>::type     right_type;
1049    typedef typename left_type::result_type   left_result_type;
1050    typedef typename middle_type::result_type middle_result_type;
1051    typedef typename right_type::result_type  right_result_type;
1052    typedef typename combine_expression<
1053        left_result_type,
1054        typename combine_expression<right_result_type, middle_result_type>::type>::type result_type;
1055    typedef tag                                                                         tag_type;
1056
1057    BOOST_MP_CXX14_CONSTEXPR expression(const Arg1& a1, const Arg2& a2, const Arg3& a3) : arg1(a1), arg2(a2), arg3(a3) {}
1058    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg1(e.arg1), arg2(e.arg2), arg3(e.arg3) {}
1059
1060 #ifndef BOOST_NO_CXX11_STATIC_ASSERT
1061    //
1062    // If we have static_assert we can give a more useful error message
1063    // than if we simply have no operator defined at all:
1064    //
1065    template <class Other>
1066    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
1067    {
1068       // This should always fail:
1069       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?");
1070       return *this;
1071    }
1072    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
1073    {
1074       // This should always fail:
1075       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?");
1076       return *this;
1077    }
1078    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
1079    {
1080       // This should always fail:
1081       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?");
1082       return *this;
1083    }
1084    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
1085    {
1086       // This should always fail:
1087       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?");
1088       return *this;
1089    }
1090    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
1091    {
1092       // This should always fail:
1093       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?");
1094       return *this;
1095    }
1096    template <class Other>
1097    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
1098    {
1099       // This should always fail:
1100       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?");
1101       return *this;
1102    }
1103    template <class Other>
1104    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
1105    {
1106       // This should always fail:
1107       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?");
1108       return *this;
1109    }
1110    template <class Other>
1111    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
1112    {
1113       // This should always fail:
1114       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?");
1115       return *this;
1116    }
1117    template <class Other>
1118    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
1119    {
1120       // This should always fail:
1121       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?");
1122       return *this;
1123    }
1124    template <class Other>
1125    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
1126    {
1127       // This should always fail:
1128       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?");
1129       return *this;
1130    }
1131    template <class Other>
1132    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
1133    {
1134       // This should always fail:
1135       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?");
1136       return *this;
1137    }
1138    template <class Other>
1139    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
1140    {
1141       // This should always fail:
1142       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?");
1143       return *this;
1144    }
1145    template <class Other>
1146    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
1147    {
1148       // This should always fail:
1149       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?");
1150       return *this;
1151    }
1152    template <class Other>
1153    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
1154    {
1155       // This should always fail:
1156       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?");
1157       return *this;
1158    }
1159    template <class Other>
1160    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
1161    {
1162       // This should always fail:
1163       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?");
1164       return *this;
1165    }
1166 #endif
1167
1168    BOOST_MP_CXX14_CONSTEXPR left_type left() const
1169    {
1170       return left_type(arg1);
1171    }
1172    BOOST_MP_CXX14_CONSTEXPR middle_type middle() const { return middle_type(arg2); }
1173    BOOST_MP_CXX14_CONSTEXPR right_type  right() const { return right_type(arg3); }
1174    BOOST_MP_CXX14_CONSTEXPR const Arg1& left_ref() const BOOST_NOEXCEPT { return arg1; }
1175    BOOST_MP_CXX14_CONSTEXPR const Arg2& middle_ref() const BOOST_NOEXCEPT { return arg2; }
1176    BOOST_MP_CXX14_CONSTEXPR const Arg3& right_ref() const BOOST_NOEXCEPT { return arg3; }
1177
1178 #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
1179 #if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
1180    //
1181    // Horrible workaround for gcc-4.6.x which always prefers the template
1182    // operator bool() rather than the non-template operator when converting to
1183    // an arithmetic type:
1184    //
1185    template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
1186    explicit operator T() const
1187    {
1188       result_type r(*this);
1189       return static_cast<bool>(r);
1190    }
1191    template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
1192    explicit operator T() const
1193    {
1194       return static_cast<T>(static_cast<result_type>(*this));
1195    }
1196 #else
1197    template <class T
1198 #ifndef __SUNPRO_CC
1199              ,
1200              typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value || !is_constructible<T, result_type>::value, int>::type = 0
1201 #endif
1202              >
1203    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
1204    {
1205       return static_cast<T>(static_cast<result_type>(*this));
1206    }
1207    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
1208    {
1209       result_type r(*this);
1210       return static_cast<bool>(r);
1211    }
1212 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
1213    BOOST_MP_FORCEINLINE explicit operator void() const
1214    {}
1215 #endif
1216 #endif
1217 #else
1218    operator unmentionable_type() const
1219    {
1220       result_type r(*this);
1221       return r ? &unmentionable::proc : 0;
1222    }
1223 #endif
1224    template <class T>
1225    BOOST_MP_CXX14_CONSTEXPR T convert_to()
1226    {
1227       result_type r(*this);
1228       return r.template convert_to<T>();
1229    }
1230
1231    static const unsigned left_depth   = left_type::depth + 1;
1232    static const unsigned middle_depth = middle_type::depth + 1;
1233    static const unsigned right_depth  = right_type::depth + 1;
1234    static const unsigned depth        = left_depth > right_depth ? (left_depth > middle_depth ? left_depth : middle_depth) : (right_depth > middle_depth ? right_depth : middle_depth);
1235
1236  private:
1237    typename expression_storage<Arg1>::type arg1;
1238    typename expression_storage<Arg2>::type arg2;
1239    typename expression_storage<Arg3>::type arg3;
1240    expression&                             operator=(const expression&);
1241 };
1242
1243 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1244 struct expression
1245 {
1246    typedef mpl::int_<4>                            arity;
1247    typedef typename arg_type<Arg1>::type           left_type;
1248    typedef typename arg_type<Arg2>::type           left_middle_type;
1249    typedef typename arg_type<Arg3>::type           right_middle_type;
1250    typedef typename arg_type<Arg4>::type           right_type;
1251    typedef typename left_type::result_type         left_result_type;
1252    typedef typename left_middle_type::result_type  left_middle_result_type;
1253    typedef typename right_middle_type::result_type right_middle_result_type;
1254    typedef typename right_type::result_type        right_result_type;
1255    typedef typename combine_expression<
1256        left_result_type,
1257        typename combine_expression<
1258            left_middle_result_type,
1259            typename combine_expression<right_middle_result_type, right_result_type>::type>::type>::type result_type;
1260    typedef tag                                                                                          tag_type;
1261
1262    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) {}
1263    BOOST_MP_CXX14_CONSTEXPR expression(const expression& e) : arg1(e.arg1), arg2(e.arg2), arg3(e.arg3), arg4(e.arg4) {}
1264
1265 #ifndef BOOST_NO_CXX11_STATIC_ASSERT
1266    //
1267    // If we have static_assert we can give a more useful error message
1268    // than if we simply have no operator defined at all:
1269    //
1270    template <class Other>
1271    BOOST_MP_CXX14_CONSTEXPR expression& operator=(const Other&)
1272    {
1273       // This should always fail:
1274       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?");
1275       return *this;
1276    }
1277    BOOST_MP_CXX14_CONSTEXPR expression& operator++()
1278    {
1279       // This should always fail:
1280       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?");
1281       return *this;
1282    }
1283    BOOST_MP_CXX14_CONSTEXPR expression& operator++(int)
1284    {
1285       // This should always fail:
1286       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?");
1287       return *this;
1288    }
1289    BOOST_MP_CXX14_CONSTEXPR expression& operator--()
1290    {
1291       // This should always fail:
1292       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?");
1293       return *this;
1294    }
1295    BOOST_MP_CXX14_CONSTEXPR expression& operator--(int)
1296    {
1297       // This should always fail:
1298       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?");
1299       return *this;
1300    }
1301    template <class Other>
1302    BOOST_MP_CXX14_CONSTEXPR expression& operator+=(const Other&)
1303    {
1304       // This should always fail:
1305       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?");
1306       return *this;
1307    }
1308    template <class Other>
1309    BOOST_MP_CXX14_CONSTEXPR expression& operator-=(const Other&)
1310    {
1311       // This should always fail:
1312       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?");
1313       return *this;
1314    }
1315    template <class Other>
1316    BOOST_MP_CXX14_CONSTEXPR expression& operator*=(const Other&)
1317    {
1318       // This should always fail:
1319       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?");
1320       return *this;
1321    }
1322    template <class Other>
1323    BOOST_MP_CXX14_CONSTEXPR expression& operator/=(const Other&)
1324    {
1325       // This should always fail:
1326       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?");
1327       return *this;
1328    }
1329    template <class Other>
1330    BOOST_MP_CXX14_CONSTEXPR expression& operator%=(const Other&)
1331    {
1332       // This should always fail:
1333       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?");
1334       return *this;
1335    }
1336    template <class Other>
1337    BOOST_MP_CXX14_CONSTEXPR expression& operator|=(const Other&)
1338    {
1339       // This should always fail:
1340       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?");
1341       return *this;
1342    }
1343    template <class Other>
1344    BOOST_MP_CXX14_CONSTEXPR expression& operator&=(const Other&)
1345    {
1346       // This should always fail:
1347       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?");
1348       return *this;
1349    }
1350    template <class Other>
1351    BOOST_MP_CXX14_CONSTEXPR expression& operator^=(const Other&)
1352    {
1353       // This should always fail:
1354       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?");
1355       return *this;
1356    }
1357    template <class Other>
1358    BOOST_MP_CXX14_CONSTEXPR expression& operator<<=(const Other&)
1359    {
1360       // This should always fail:
1361       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?");
1362       return *this;
1363    }
1364    template <class Other>
1365    BOOST_MP_CXX14_CONSTEXPR expression& operator>>=(const Other&)
1366    {
1367       // This should always fail:
1368       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?");
1369       return *this;
1370    }
1371 #endif
1372
1373    BOOST_MP_CXX14_CONSTEXPR left_type left() const
1374    {
1375       return left_type(arg1);
1376    }
1377    BOOST_MP_CXX14_CONSTEXPR left_middle_type  left_middle() const { return left_middle_type(arg2); }
1378    BOOST_MP_CXX14_CONSTEXPR right_middle_type right_middle() const { return right_middle_type(arg3); }
1379    BOOST_MP_CXX14_CONSTEXPR right_type        right() const { return right_type(arg4); }
1380    BOOST_MP_CXX14_CONSTEXPR const Arg1&       left_ref() const BOOST_NOEXCEPT { return arg1; }
1381    BOOST_MP_CXX14_CONSTEXPR const Arg2&       left_middle_ref() const BOOST_NOEXCEPT { return arg2; }
1382    BOOST_MP_CXX14_CONSTEXPR const Arg3&       right_middle_ref() const BOOST_NOEXCEPT { return arg3; }
1383    BOOST_MP_CXX14_CONSTEXPR const Arg4&       right_ref() const BOOST_NOEXCEPT { return arg4; }
1384
1385 #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
1386 #if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
1387    //
1388    // Horrible workaround for gcc-4.6.x which always prefers the template
1389    // operator bool() rather than the non-template operator when converting to
1390    // an arithmetic type:
1391    //
1392    template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
1393    explicit operator T() const
1394    {
1395       result_type r(*this);
1396       return static_cast<bool>(r);
1397    }
1398    template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
1399    explicit operator T() const
1400    {
1401       return static_cast<T>(static_cast<result_type>(*this));
1402    }
1403 #else
1404    template <class T
1405 #ifndef __SUNPRO_CC
1406              ,
1407              typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value || !is_constructible<T, result_type>::value, int>::type = 0
1408 #endif
1409              >
1410    explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
1411    {
1412       return static_cast<T>(static_cast<result_type>(*this));
1413    }
1414    BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
1415    {
1416       result_type r(*this);
1417       return static_cast<bool>(r);
1418    }
1419 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
1420    BOOST_MP_FORCEINLINE explicit operator void() const
1421    {}
1422 #endif
1423 #endif
1424 #else
1425    operator unmentionable_type() const
1426    {
1427       result_type r(*this);
1428       return r ? &unmentionable::proc : 0;
1429    }
1430 #endif
1431    template <class T>
1432    BOOST_MP_CXX14_CONSTEXPR T convert_to()
1433    {
1434       result_type r(*this);
1435       return r.template convert_to<T>();
1436    }
1437
1438    static const unsigned left_depth         = left_type::depth + 1;
1439    static const unsigned left_middle_depth  = left_middle_type::depth + 1;
1440    static const unsigned right_middle_depth = right_middle_type::depth + 1;
1441    static const unsigned right_depth        = right_type::depth + 1;
1442
1443    static const unsigned left_max_depth  = left_depth > left_middle_depth ? left_depth : left_middle_depth;
1444    static const unsigned right_max_depth = right_depth > right_middle_depth ? right_depth : right_middle_depth;
1445
1446    static const unsigned depth = left_max_depth > right_max_depth ? left_max_depth : right_max_depth;
1447
1448  private:
1449    typename expression_storage<Arg1>::type arg1;
1450    typename expression_storage<Arg2>::type arg2;
1451    typename expression_storage<Arg3>::type arg3;
1452    typename expression_storage<Arg4>::type arg4;
1453    expression&                             operator=(const expression&);
1454 };
1455
1456 template <class T>
1457 struct digits2
1458 {
1459    BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_specialized);
1460    BOOST_STATIC_ASSERT((std::numeric_limits<T>::radix == 2) || (std::numeric_limits<T>::radix == 10));
1461    // If we really have so many digits that this fails, then we're probably going to hit other problems anyway:
1462    BOOST_STATIC_ASSERT(LONG_MAX / 1000 > (std::numeric_limits<T>::digits + 1));
1463    static const long                  m_value = std::numeric_limits<T>::radix == 10 ? (((std::numeric_limits<T>::digits + 1) * 1000L) / 301L) : std::numeric_limits<T>::digits;
1464    static inline BOOST_CONSTEXPR long value() BOOST_NOEXCEPT { return m_value; }
1465 };
1466
1467 #ifndef BOOST_MP_MIN_EXPONENT_DIGITS
1468 #ifdef _MSC_VER
1469 #define BOOST_MP_MIN_EXPONENT_DIGITS 2
1470 #else
1471 #define BOOST_MP_MIN_EXPONENT_DIGITS 2
1472 #endif
1473 #endif
1474
1475 template <class S>
1476 void format_float_string(S& str, boost::intmax_t my_exp, boost::intmax_t digits, std::ios_base::fmtflags f, bool iszero)
1477 {
1478    typedef typename S::size_type size_type;
1479    bool                          scientific = (f & std::ios_base::scientific) == std::ios_base::scientific;
1480    bool                          fixed      = (f & std::ios_base::fixed) == std::ios_base::fixed;
1481    bool                          showpoint  = (f & std::ios_base::showpoint) == std::ios_base::showpoint;
1482    bool                          showpos    = (f & std::ios_base::showpos) == std::ios_base::showpos;
1483
1484    bool neg = str.size() && (str[0] == '-');
1485
1486    if (neg)
1487       str.erase(0, 1);
1488
1489    if (digits == 0)
1490    {
1491       digits = (std::max)(str.size(), size_type(16));
1492    }
1493
1494    if (iszero || str.empty() || (str.find_first_not_of('0') == S::npos))
1495    {
1496       // We will be printing zero, even though the value might not
1497       // actually be zero (it just may have been rounded to zero).
1498       str = "0";
1499       if (scientific || fixed)
1500       {
1501          str.append(1, '.');
1502          str.append(size_type(digits), '0');
1503          if (scientific)
1504             str.append("e+00");
1505       }
1506       else
1507       {
1508          if (showpoint)
1509          {
1510             str.append(1, '.');
1511             if (digits > 1)
1512                str.append(size_type(digits - 1), '0');
1513          }
1514       }
1515       if (neg)
1516          str.insert(static_cast<std::string::size_type>(0), 1, '-');
1517       else if (showpos)
1518          str.insert(static_cast<std::string::size_type>(0), 1, '+');
1519       return;
1520    }
1521
1522    if (!fixed && !scientific && !showpoint)
1523    {
1524       //
1525       // Suppress trailing zeros:
1526       //
1527       std::string::iterator pos = str.end();
1528       while (pos != str.begin() && *--pos == '0')
1529       {
1530       }
1531       if (pos != str.end())
1532          ++pos;
1533       str.erase(pos, str.end());
1534       if (str.empty())
1535          str = '0';
1536    }
1537    else if (!fixed || (my_exp >= 0))
1538    {
1539       //
1540       // Pad out the end with zero's if we need to:
1541       //
1542       boost::intmax_t chars = str.size();
1543       chars                 = digits - chars;
1544       if (scientific)
1545          ++chars;
1546       if (chars > 0)
1547       {
1548          str.append(static_cast<std::string::size_type>(chars), '0');
1549       }
1550    }
1551
1552    if (fixed || (!scientific && (my_exp >= -4) && (my_exp < digits)))
1553    {
1554       if (1 + my_exp > static_cast<boost::intmax_t>(str.size()))
1555       {
1556          // Just pad out the end with zeros:
1557          str.append(static_cast<std::string::size_type>(1 + my_exp - str.size()), '0');
1558          if (showpoint || fixed)
1559             str.append(".");
1560       }
1561       else if (my_exp + 1 < static_cast<boost::intmax_t>(str.size()))
1562       {
1563          if (my_exp < 0)
1564          {
1565             str.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(-1 - my_exp), '0');
1566             str.insert(static_cast<std::string::size_type>(0), "0.");
1567          }
1568          else
1569          {
1570             // Insert the decimal point:
1571             str.insert(static_cast<std::string::size_type>(my_exp + 1), 1, '.');
1572          }
1573       }
1574       else if (showpoint || fixed) // we have exactly the digits we require to left of the point
1575          str += ".";
1576
1577       if (fixed)
1578       {
1579          // We may need to add trailing zeros:
1580          boost::intmax_t l = str.find('.') + 1;
1581          l                 = digits - (str.size() - l);
1582          if (l > 0)
1583             str.append(size_type(l), '0');
1584       }
1585    }
1586    else
1587    {
1588       BOOST_MP_USING_ABS
1589       // Scientific format:
1590       if (showpoint || (str.size() > 1))
1591          str.insert(static_cast<std::string::size_type>(1u), 1, '.');
1592       str.append(static_cast<std::string::size_type>(1u), 'e');
1593       S e = boost::lexical_cast<S>(abs(my_exp));
1594       if (e.size() < BOOST_MP_MIN_EXPONENT_DIGITS)
1595          e.insert(static_cast<std::string::size_type>(0), BOOST_MP_MIN_EXPONENT_DIGITS - e.size(), '0');
1596       if (my_exp < 0)
1597          e.insert(static_cast<std::string::size_type>(0), 1, '-');
1598       else
1599          e.insert(static_cast<std::string::size_type>(0), 1, '+');
1600       str.append(e);
1601    }
1602    if (neg)
1603       str.insert(static_cast<std::string::size_type>(0), 1, '-');
1604    else if (showpos)
1605       str.insert(static_cast<std::string::size_type>(0), 1, '+');
1606 }
1607
1608 template <class V>
1609 BOOST_MP_CXX14_CONSTEXPR void check_shift_range(V val, const mpl::true_&, const mpl::true_&)
1610 {
1611    if (val > (std::numeric_limits<std::size_t>::max)())
1612       BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a value greater than std::numeric_limits<std::size_t>::max()."));
1613    if (val < 0)
1614       BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a negative value."));
1615 }
1616 template <class V>
1617 BOOST_MP_CXX14_CONSTEXPR void check_shift_range(V val, const mpl::false_&, const mpl::true_&)
1618 {
1619    if (val < 0)
1620       BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a negative value."));
1621 }
1622 template <class V>
1623 BOOST_MP_CXX14_CONSTEXPR void check_shift_range(V val, const mpl::true_&, const mpl::false_&)
1624 {
1625    if (val > (std::numeric_limits<std::size_t>::max)())
1626       BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a value greater than std::numeric_limits<std::size_t>::max()."));
1627 }
1628 template <class V>
1629 BOOST_MP_CXX14_CONSTEXPR void check_shift_range(V, const mpl::false_&, const mpl::false_&) BOOST_NOEXCEPT {}
1630
1631 template <class T>
1632 BOOST_MP_CXX14_CONSTEXPR const T& evaluate_if_expression(const T& val) { return val; }
1633 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1634 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; }
1635
1636 } // namespace detail
1637
1638 //
1639 // Traits class, lets us know what kind of number we have, defaults to a floating point type:
1640 //
1641 enum number_category_type
1642 {
1643    number_kind_unknown        = -1,
1644    number_kind_integer        = 0,
1645    number_kind_floating_point = 1,
1646    number_kind_rational       = 2,
1647    number_kind_fixed_point    = 3,
1648    number_kind_complex        = 4
1649 };
1650
1651 template <class Num, bool, bool>
1652 struct number_category_base : public mpl::int_<number_kind_unknown>
1653 {};
1654 template <class Num>
1655 struct number_category_base<Num, true, false> : public mpl::int_<std::numeric_limits<Num>::is_integer ? number_kind_integer : (std::numeric_limits<Num>::max_exponent ? number_kind_floating_point : number_kind_unknown)>
1656 {};
1657 template <class Num>
1658 struct number_category : public number_category_base<Num, boost::is_class<Num>::value || boost::is_arithmetic<Num>::value, boost::is_abstract<Num>::value>
1659 {};
1660 template <class Backend, expression_template_option ExpressionTemplates>
1661 struct number_category<number<Backend, ExpressionTemplates> > : public number_category<Backend>
1662 {};
1663 template <class tag, class A1, class A2, class A3, class A4>
1664 struct number_category<detail::expression<tag, A1, A2, A3, A4> > : public number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>
1665 {};
1666 //
1667 // Specializations for types which do not always have numberic_limits specializations:
1668 //
1669 #ifdef BOOST_HAS_INT128
1670 template <>
1671 struct number_category<boost::int128_type> : public mpl::int_<number_kind_integer>
1672 {};
1673 template <>
1674 struct number_category<boost::uint128_type> : public mpl::int_<number_kind_integer>
1675 {};
1676 #endif
1677 #ifdef BOOST_HAS_FLOAT128
1678 template <>
1679 struct number_category<__float128> : public mpl::int_<number_kind_floating_point>
1680 {};
1681 #endif
1682
1683 template <class T>
1684 struct component_type
1685 {
1686    typedef T type;
1687 };
1688 template <class tag, class A1, class A2, class A3, class A4>
1689 struct component_type<detail::expression<tag, A1, A2, A3, A4> > : public component_type<typename detail::expression<tag, A1, A2, A3, A4>::result_type>
1690 {};
1691
1692 template <class T>
1693 struct scalar_result_from_possible_complex
1694 {
1695    typedef typename mpl::if_c<number_category<T>::value == number_kind_complex,
1696                               typename component_type<T>::type, T>::type type;
1697 };
1698
1699 template <class T>
1700 struct complex_result_from_scalar; // individual backends must specialize this trait.
1701
1702 template <class T>
1703 struct is_unsigned_number : public mpl::false_
1704 {};
1705 template <class Backend, expression_template_option ExpressionTemplates>
1706 struct is_unsigned_number<number<Backend, ExpressionTemplates> > : public is_unsigned_number<Backend>
1707 {};
1708 template <class T>
1709 struct is_signed_number : public mpl::bool_<!is_unsigned_number<T>::value>
1710 {};
1711 template <class T>
1712 struct is_interval_number : public mpl::false_
1713 {};
1714 template <class Backend, expression_template_option ExpressionTemplates>
1715 struct is_interval_number<number<Backend, ExpressionTemplates> > : public is_interval_number<Backend>
1716 {};
1717
1718 } // namespace multiprecision
1719 } // namespace boost
1720
1721 namespace boost { namespace math {
1722    namespace tools {
1723
1724       template <class T>
1725       struct promote_arg;
1726
1727       template <class tag, class A1, class A2, class A3, class A4>
1728       struct promote_arg<boost::multiprecision::detail::expression<tag, A1, A2, A3, A4> >
1729       {
1730          typedef typename boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type type;
1731       };
1732
1733       template <class R, class B, boost::multiprecision::expression_template_option ET>
1734       inline R real_cast(const boost::multiprecision::number<B, ET>& val)
1735       {
1736          return val.template convert_to<R>();
1737       }
1738
1739       template <class R, class tag, class A1, class A2, class A3, class A4>
1740       inline R real_cast(const boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>& val)
1741       {
1742          typedef typename boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type val_type;
1743          return val_type(val).template convert_to<R>();
1744       }
1745
1746       template <class B, boost::multiprecision::expression_template_option ET>
1747       struct is_complex_type<boost::multiprecision::number<B, ET> > : public boost::mpl::bool_<boost::multiprecision::number_category<B>::value == boost::multiprecision::number_kind_complex> {};
1748
1749 } // namespace tools
1750
1751 namespace constants {
1752
1753 template <class T>
1754 struct is_explicitly_convertible_from_string;
1755
1756 template <class B, boost::multiprecision::expression_template_option ET>
1757 struct is_explicitly_convertible_from_string<boost::multiprecision::number<B, ET> >
1758 {
1759    static const bool value = true;
1760 };
1761
1762 } // namespace constants
1763
1764 }} // namespace boost::math
1765
1766 #ifdef BOOST_MSVC
1767 #pragma warning(pop)
1768 #endif
1769
1770 #endif // BOOST_MATH_BIG_NUM_BASE_HPP