boost rational is tripping up one of my examples in safe numerics: // solution: use safe integer in rational definition using safe_rational = boost::rational< boost::safe_numerics::safe<int> >; // use rationals created with safe_t const safe_rational sc {1, std::numeric_limits<int>::max()}; std::cout << "c = " << sc << std::endl; const safe_rational sd {1, 2}; std::cout << "d = " << sd << std::endl; std::cout << "c * d = "; try { // multiply them. This will overflow std::cout << sc * sd << std::endl; // use of overload operator * is ambiguous. rational.hpp contains - among other things, the following definitions for the * operator: template <class IntType, class Arg> BOOST_CXX14_CONSTEXPR inline typename boost::enable_if_c < rational_detail::is_compatible_integer<Arg, IntType>::value || is_same<rational<IntType>, Arg>::value, rational<IntType> >::type operator * (const rational<IntType>& a, const Arg& b) { rational<IntType> t(a); return t *= b; } template <class Arg, class IntType> BOOST_CXX14_CONSTEXPR inline typename boost::enable_if_c < rational_detail::is_compatible_integer<Arg, IntType>::value, rational<IntType> >::type operator * (const Arg& b, const rational<IntType>& a) { rational<IntType> t(a); return t *= b; } Soooooo - it seems that sc * sd will match both of the above definitions. Its unclear what the purpose of these two different overloads are. They look pretty similar to me. the definition for is_compatible_integer. namespace rational_detail{ template <class FromInt, class ToInt, typename Enable = void> struct is_compatible_integer; template <class FromInt, class ToInt> struct is_compatible_integer<FromInt, ToInt, typename enable_if_c<!is_array<FromInt>::value>::type> { BOOST_STATIC_CONSTANT(bool, value = ((std::numeric_limits<FromInt>::is_specialized && std::numeric_limits<FromInt>::is_integer && (std::numeric_limits<FromInt>::digits <=std::numeric_limits<ToInt>::digits) && (std::numeric_limits<FromInt>::radix == std::numeric_limits<ToInt>::radix) && ((std::numeric_limits<FromInt>::is_signed == false) || (std::numeric_limits<ToInt>::is_signed == true)) && is_convertible<FromInt, ToInt>::value) || is_same<FromInt, ToInt>::value) || (is_class<ToInt>::value && is_class<FromInt>::value && is_convertible<FromInt, ToInt>::value)); }; ... In fact, since it looks like if FromInt and ToInt are the same types (as they are in my case, one will always got more than one match. Is anyone (John Maddock - where are you?) able to shed some light on this for me? Robert Ramey