diff --git a/include/boost/multiprecision/detail/number_base.hpp b/include/boost/multiprecision/detail/number_base.hpp index 09c86e6c..321e356f 100644 --- a/include/boost/multiprecision/detail/number_base.hpp +++ b/include/boost/multiprecision/detail/number_base.hpp @@ -360,11 +360,36 @@ struct expression static const unsigned depth = left_type::depth + 1; #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS - explicit operator bool()const +# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) + // + // Horrible workaround for gcc-4.6.x which always prefers the template + // operator bool() rather than the non-template operator when converting to + // an arithmetic type: + // + template , int>::type = 0> + explicit operator T ()const { result_type r(*this); return static_cast(r); } + template ::value || is_void::value || is_number::value, int>::type = 0> + explicit operator T ()const + { + return static_cast(static_cast(*this)); + } +# else + template ::value, int>::type = 0> + explicit operator T()const + { + return static_cast(static_cast(*this)); + } + BOOST_MP_FORCEINLINE explicit operator bool()const + { + result_type r(*this); + return static_cast(r); + } + explicit operator void()const {} +# endif #else operator unmentionable_type()const { @@ -373,6 +398,13 @@ struct expression } #endif + template + T convert_to() + { + result_type r(*this); + return r.template convert_to(); + } + private: typename expression_storage::type arg; expression& operator=(const expression&); @@ -392,10 +424,36 @@ struct expression static const unsigned depth = 0; #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS - explicit operator bool()const +# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) + // + // Horrible workaround for gcc-4.6.x which always prefers the template + // operator bool() rather than the non-template operator when converting to + // an arithmetic type: + // + template , int>::type = 0> + explicit operator T ()const { - return static_cast(arg); + result_type r(*this); + return static_cast(r); +} + template ::value || is_void::value || is_number::value, int>::type = 0> + explicit operator T ()const + { + return static_cast(static_cast(*this)); } +# else + template ::value, int>::type = 0> + explicit operator T()const + { + return static_cast(static_cast(*this)); + } + BOOST_MP_FORCEINLINE explicit operator bool()const + { + result_type r(*this); + return static_cast(r); + } + explicit operator void()const {} +# endif #else operator unmentionable_type()const { @@ -403,6 +461,13 @@ struct expression } #endif + template + T convert_to() + { + result_type r(*this); + return r.template convert_to(); + } + private: typename expression_storage::type arg; expression& operator=(const expression&); @@ -427,11 +492,36 @@ struct expression const Arg2& right_ref()const BOOST_NOEXCEPT { return arg2; } #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS - explicit operator bool()const +# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) + // + // Horrible workaround for gcc-4.6.x which always prefers the template + // operator bool() rather than the non-template operator when converting to + // an arithmetic type: + // + template , int>::type = 0> + explicit operator T ()const + { + result_type r(*this); + return static_cast(r); +} + template ::value || is_void::value || is_number::value, int>::type = 0> + explicit operator T ()const + { + return static_cast(static_cast(*this)); + } +# else + template ::value, int>::type = 0> + explicit operator T()const + { + return static_cast(static_cast(*this)); + } + BOOST_MP_FORCEINLINE explicit operator bool()const { result_type r(*this); return static_cast(r); } + explicit operator void()const {} +# endif #else operator unmentionable_type()const { @@ -439,6 +529,13 @@ struct expression return r ? &unmentionable::proc : 0; } #endif + template + T convert_to() + { + result_type r(*this); + return r.template convert_to(); + } + static const unsigned left_depth = left_type::depth + 1; static const unsigned right_depth = right_type::depth + 1; static const unsigned depth = left_depth > right_depth ? left_depth : right_depth; @@ -474,11 +571,36 @@ struct expression const Arg3& right_ref()const BOOST_NOEXCEPT { return arg3; } #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS - explicit operator bool()const +# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) + // + // Horrible workaround for gcc-4.6.x which always prefers the template + // operator bool() rather than the non-template operator when converting to + // an arithmetic type: + // + template , int>::type = 0> + explicit operator T ()const + { + result_type r(*this); + return static_cast(r); +} + template ::value || is_void::value || is_number::value, int>::type = 0> + explicit operator T ()const + { + return static_cast(static_cast(*this)); + } +# else + template ::value, int>::type = 0> + explicit operator T()const + { + return static_cast(static_cast(*this)); + } + BOOST_MP_FORCEINLINE explicit operator bool()const { result_type r(*this); return static_cast(r); } + explicit operator void()const {} +# endif #else operator unmentionable_type()const { @@ -486,6 +608,13 @@ struct expression return r ? &unmentionable::proc : 0; } #endif + template + T convert_to() + { + result_type r(*this); + return r.template convert_to(); + } + static const unsigned left_depth = left_type::depth + 1; static const unsigned middle_depth = middle_type::depth + 1; static const unsigned right_depth = right_type::depth + 1; @@ -530,11 +659,36 @@ struct expression const Arg4& right_ref()const BOOST_NOEXCEPT { return arg4; } #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS - explicit operator bool()const +# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) + // + // Horrible workaround for gcc-4.6.x which always prefers the template + // operator bool() rather than the non-template operator when converting to + // an arithmetic type: + // + template , int>::type = 0> + explicit operator T ()const + { + result_type r(*this); + return static_cast(r); +} + template ::value || is_void::value || is_number::value, int>::type = 0> + explicit operator T ()const + { + return static_cast(static_cast(*this)); + } +# else + template ::value, int>::type = 0> + explicit operator T()const + { + return static_cast(static_cast(*this)); + } + BOOST_MP_FORCEINLINE explicit operator bool()const { result_type r(*this); return static_cast(r); } + explicit operator void()const {} +# endif #else operator unmentionable_type()const { @@ -542,6 +696,13 @@ struct expression return r ? &unmentionable::proc : 0; } #endif + template + T convert_to() + { + result_type r(*this); + return r.template convert_to(); + } + static const unsigned left_depth = left_type::depth + 1; static const unsigned left_middle_depth = left_middle_type::depth + 1; static const unsigned right_middle_depth = right_middle_type::depth + 1; diff --git a/test/test_arithmetic.hpp b/test/test_arithmetic.hpp index d787f938..e6d1fdd9 100644 --- a/test/test_arithmetic.hpp +++ b/test/test_arithmetic.hpp @@ -958,6 +958,17 @@ void test_negative_mixed(boost::mpl::true_ const&) BOOST_CHECK_EQUAL(static_cast(Real(n2)) , n2); BOOST_CHECK_EQUAL(static_cast(Real(n3)) , n3); BOOST_CHECK_EQUAL(static_cast(Real(n4)) , n4); +#endif + // Conversions when source is an expression template: + BOOST_CHECK_EQUAL((Real(n1) + 0).template convert_to() , n1); + BOOST_CHECK_EQUAL((Real(n2) + 0).template convert_to(), n2); + BOOST_CHECK_EQUAL((Real(n3) + 0).template convert_to(), n3); + BOOST_CHECK_EQUAL((Real(n4) + 0).template convert_to(), n4); +#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + BOOST_CHECK_EQUAL(static_cast((Real(n1) + 0)), n1); + BOOST_CHECK_EQUAL(static_cast((Real(n2) + 0)), n2); + BOOST_CHECK_EQUAL(static_cast((Real(n3) + 0)), n3); + BOOST_CHECK_EQUAL(static_cast((Real(n4) + 0)), n4); #endif #if defined(TEST_MPFR) Num tol = 10 * std::numeric_limits::epsilon(); @@ -1250,7 +1261,18 @@ void test_mixed(const boost::mpl::true_&) BOOST_CHECK_EQUAL(static_cast(Real(n3)) , n3); BOOST_CHECK_EQUAL(static_cast(Real(n4)) , n4); #endif - BOOST_CHECK_EQUAL(static_cast(n1) , Real(n1)); + // Again with expression templates: + BOOST_CHECK_EQUAL((Real(n1) + 0).template convert_to(), n1); + BOOST_CHECK_EQUAL((Real(n2) + 0).template convert_to(), n2); + BOOST_CHECK_EQUAL((Real(n3) + 0).template convert_to(), n3); + BOOST_CHECK_EQUAL((Real(n4) + 0).template convert_to(), n4); +#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + BOOST_CHECK_EQUAL(static_cast(Real(n1) + 0), n1); + BOOST_CHECK_EQUAL(static_cast(Real(n2) + 0), n2); + BOOST_CHECK_EQUAL(static_cast(Real(n3) + 0), n3); + BOOST_CHECK_EQUAL(static_cast(Real(n4) + 0), n4); +#endif + BOOST_CHECK_EQUAL(static_cast(n1), Real(n1)); BOOST_CHECK_EQUAL(static_cast(n2) , Real(n2)); BOOST_CHECK_EQUAL(static_cast(n3) , Real(n3)); BOOST_CHECK_EQUAL(static_cast(n4) , Real(n4));