diff --git a/include/boost/rational.hpp b/include/boost/rational.hpp index 89d2fb4..38a4bd3 100644 --- a/include/boost/rational.hpp +++ b/include/boost/rational.hpp @@ -965,11 +965,12 @@ std::istream& operator>> (std::istream& is, rational& r) } // Add manipulators for output format? -template -std::ostream& operator<< (std::ostream& os, const rational& r) +template +std::basic_ostream& operator<< (std::basic_ostream& os, + const rational& r) { // The slash directly precedes the denominator, which has no prefixes. - std::ostringstream ss; + std::basic_ostringstream ss; ss.copyfmt( os ); ss.tie( NULL ); @@ -978,12 +979,12 @@ std::ostream& operator<< (std::ostream& os, const rational& r) ss << std::noshowpos << std::noshowbase << '/' << r.denominator(); // The numerator holds the showpos, internal, and showbase flags. - std::string const tail = ss.str(); + std::basic_string const tail = ss.str(); std::streamsize const w = os.width() - static_cast( tail.size() ); ss.clear(); - ss.str( "" ); + ss.str( std::basic_string() ); ss.flags( os.flags() ); ss << std::setw( w < 0 || (os.flags() & std::ios::adjustfield) != std::ios::internal ? 0 : w ) << r.numerator(); diff --git a/rational.html b/rational.html index ebacab7..f25df5f 100644 --- a/rational.html +++ b/rational.html @@ -121,7 +121,8 @@

Class rational synopsis

// Input and output template <typename I> std::istream& operator>> (std::istream& is, rational<I>& r); -template <typename I> std::ostream& operator<< (std::ostream& os, const rational<I>& r); +template <typename I, typename Ch, typename Tr> +std::basic_ostream<Ch, Tr>& operator<< (std::basic_ostream<Ch, Tr>& os, const rational<I>& r); // Type conversion template <typename T, typename I> T rational_cast (const rational<I>& r); // constexpr since C++11 diff --git a/test/rational_test.cpp b/test/rational_test.cpp index ccd58ea..46dd887 100644 --- a/test/rational_test.cpp +++ b/test/rational_test.cpp @@ -1176,6 +1176,43 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( rational_output_test, T, all_signed_test_types ) BOOST_CHECK_EQUAL( oss.str(), "0x22/3db" ); // not "0x22/0x3db" } +#if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_STD_WSTREAMBUF) +BOOST_AUTO_TEST_CASE_TEMPLATE( rational_wide_output_test, T, + builtin_signed_test_types ) +{ + using namespace std; + typedef boost::rational rational_type; + + wostringstream oss; + + oss << rational_type( 44, 14 ); + BOOST_CHECK( oss.str() == L"22/7" ); + + // Rational output must not fall back to Boolean conversion. + oss.clear(); oss.str( L"" ); + oss << boolalpha << rational_type( 0 ) << L' ' << rational_type( 1, 3 ); + BOOST_CHECK( oss.str() == L"0/1 1/3" ); + + oss.clear(); oss.str( L"" ); + oss << setw( 5 ) << setfill(L'*') << rational_type( 1, 2 ) << L'r'; + BOOST_CHECK( oss.str() == L"**1/2r" ); + BOOST_CHECK_EQUAL( oss.width(), 0 ); + BOOST_CHECK_EQUAL( oss.fill(), L'*' ); + + oss.clear(); oss.str( L"" ); + oss << showpos << rational_type( 2, 3 ) << noshowpos; + BOOST_CHECK( oss.str() == L"+2/3" ); + + oss.clear(); oss.str( L"" ); + oss << setw( 8 ) << internal << rational_type( 36, -15 ) << right << L'r'; + BOOST_CHECK( oss.str() == L"-***12/5r" ); + + oss.clear(); oss.str( L"" ); + oss << showbase << hex << rational_type( 34, 987 ) << noshowbase << dec; + BOOST_CHECK( oss.str() == L"0x22/3db" ); +} +#endif + // Input test, failing BOOST_AUTO_TEST_CASE_TEMPLATE( rational_input_failing_test, T, all_signed_test_types )