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

source code of boost/libs/multiprecision/include/boost/multiprecision/detail/number_base.hpp