Skip to content

Commit

Permalink
Disable explicit conversions on expression templates when the target …
Browse files Browse the repository at this point in the history
…type is implicitly constructible from the number type.

See https://svn.boost.org/trac/boost/ticket/11922
  • Loading branch information
jzmaddock committed Jan 20, 2016
1 parent 95b8a52 commit df773c7
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 10 deletions.
21 changes: 11 additions & 10 deletions include/boost/multiprecision/detail/number_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <limits>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_constructible.hpp>
#include <boost/type_traits/decay.hpp>
#ifdef BOOST_MSVC
# pragma warning(push)
Expand Down Expand Up @@ -379,7 +380,7 @@ struct expression<tag, Arg1, void, void, void>

static const unsigned depth = left_type::depth + 1;
#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (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
Expand All @@ -397,7 +398,7 @@ struct expression<tag, Arg1, void, void, void>
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
Expand Down Expand Up @@ -443,7 +444,7 @@ struct expression<terminal, Arg1, void, void, void>
static const unsigned depth = 0;

#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (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
Expand All @@ -461,7 +462,7 @@ struct expression<terminal, Arg1, void, void, void>
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
Expand Down Expand Up @@ -511,7 +512,7 @@ struct expression<tag, Arg1, Arg2, void, void>
const Arg2& right_ref()const BOOST_NOEXCEPT { return arg2; }

#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (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
Expand All @@ -529,7 +530,7 @@ struct expression<tag, Arg1, Arg2, void, void>
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
Expand Down Expand Up @@ -590,7 +591,7 @@ struct expression<tag, Arg1, Arg2, Arg3, void>
const Arg3& right_ref()const BOOST_NOEXCEPT { return arg3; }

#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (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
Expand All @@ -608,7 +609,7 @@ struct expression<tag, Arg1, Arg2, Arg3, void>
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
Expand Down Expand Up @@ -678,7 +679,7 @@ struct expression
const Arg4& right_ref()const BOOST_NOEXCEPT { return arg4; }

#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (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
Expand All @@ -696,7 +697,7 @@ struct expression
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
template <class T, typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
Expand Down
4 changes: 4 additions & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,10 @@ run test_mixed_mpfr_float.cpp mpfr gmp : : : [ check-target-builds ../config//h
# Check for narrowing conversions:
#
run test_float_conversions.cpp ;
#
# specific bug cases:
#
compile bug11922.cpp ;

if $(enable-specfun)
{
Expand Down
49 changes: 49 additions & 0 deletions test/bug11922.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2016 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include <boost/multiprecision/cpp_int.hpp>
#include <memory>

typedef boost::multiprecision::cpp_int mp_int;

#if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) && !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)

class Int1 {
public:
Int1(const mp_int& i) {}
Int1(const Int1& i) {}
};

class Int2 {
public:
Int2(const mp_int& i) {}
Int2(const Int2& i) = delete;
};


int main()
{
using namespace boost::multiprecision;

mp_int i(10);
Int1 a(i + 10);
Int2 b(i + 20);

#ifndef BOOST_NO_CXX11_SMART_PTR

std::shared_ptr<Int1> p1 = std::make_shared<Int1>(i + 10);
std::shared_ptr<Int2> p2 = std::make_shared<Int2>(i + 10);

#endif

return 0;
}

#else

int main() { return 0; }

#endif

0 comments on commit df773c7

Please sign in to comment.