diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index dfd833d..cf1d700 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1394,14 +1394,7 @@ namespace boost { } template -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - bool shl_input_streamable(InputStreamable&& input) { - typedef InputStreamable&& forward_type; -#else bool shl_input_streamable(InputStreamable& input) { - typedef InputStreamable& forward_type; -#endif // BOOST_NO_CXX11_RVALUE_REFERENCES - #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE) // If you have compilation error at this point, than your STL library // does not support such conversions. Try updating it. @@ -1412,7 +1405,7 @@ namespace boost { out_stream.exceptions(std::ios::badbit); try { #endif - bool const result = !(out_stream << static_cast(input)).fail(); + bool const result = !(out_stream << input).fail(); const buffer_t* const p = static_cast( static_cast*>(out_stream.rdbuf()) ); @@ -1673,7 +1666,6 @@ namespace boost { return ((*this) << reinterpret_cast const& >(input)); } #endif - template bool operator<<(const InStreamable& input) { return shl_input_streamable(input); } }; @@ -2081,21 +2073,14 @@ namespace boost { BOOST_DEDUCED_TYPENAME stream_trait::traits > o_interpreter_type; -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - template - static inline bool try_convert(T&& arg, Target& result) { - typedef T&& forward_type; -#else static inline bool try_convert(const Source& arg, Target& result) { - typedef const Source& forward_type; -#endif i_interpreter_type i_interpreter; // Disabling ADL, by directly specifying operators. // // For compilers with perfect forwarding `static_cast(arg)` is // eqaul to `std::forward(arg)`. - if (!(i_interpreter.operator <<(static_cast(arg)))) + if (!(i_interpreter.operator <<(arg))) return false; o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend()); @@ -2263,56 +2248,76 @@ namespace boost { }; } + namespace conversion { namespace detail { #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - template - inline bool try_lexical_convert(Source&& arg, Target& result) - { - typedef BOOST_DEDUCED_TYPENAME boost::remove_const< - BOOST_DEDUCED_TYPENAME boost::remove_reference::type - >::type no_cr_source_t; + template + inline bool try_lexical_convert(Source&& arg, Target& result) + { + typedef BOOST_DEDUCED_TYPENAME boost::remove_const< + BOOST_DEDUCED_TYPENAME boost::remove_reference::type + >::type no_cr_source_t; - typedef Source&& forward_type; + typedef Source&& forward_type; #else - template - inline bool try_lexical_convert(const Source& arg, Target& result) - { - typedef Source no_cr_source_t; - typedef const Source& forward_type; + template + inline bool try_lexical_convert(const Source& arg, Target& result) + { + typedef Source no_cr_source_t; + typedef const Source& forward_type; #endif - typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay::type src; + typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay::type src; - typedef BOOST_DEDUCED_TYPENAME boost::type_traits::ice_or< - boost::detail::is_xchar_to_xchar::value, - boost::detail::is_char_array_to_stdstring::value, - boost::type_traits::ice_and< - boost::is_same::value, - boost::detail::is_stdstring::value - >::value, - boost::type_traits::ice_and< - boost::is_same::value, - boost::detail::is_character::value - >::value - > shall_we_copy_t; + typedef BOOST_DEDUCED_TYPENAME boost::type_traits::ice_or< + boost::detail::is_xchar_to_xchar::value, + boost::detail::is_char_array_to_stdstring::value, + boost::type_traits::ice_and< + boost::is_same::value, + boost::detail::is_stdstring::value + >::value, + boost::type_traits::ice_and< + boost::is_same::value, + boost::detail::is_character::value + >::value + > shall_we_copy_t; - typedef boost::detail::is_arithmetic_and_not_xchars - shall_we_copy_with_dynamic_check_t; + typedef boost::detail::is_arithmetic_and_not_xchars + shall_we_copy_with_dynamic_check_t; - // We do evaluate second `if_` lazily to avoid unnecessary instantiations - // of `shall_we_copy_with_dynamic_check_t` and improve compilation times. - typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< - shall_we_copy_t::value, - boost::mpl::identity >, - boost::mpl::if_< - shall_we_copy_with_dynamic_check_t, - boost::detail::dynamic_num_converter_impl, - boost::detail::lexical_converter_impl - > - >::type caster_type_lazy; + // We do evaluate second `if_` lazily to avoid unnecessary instantiations + // of `shall_we_copy_with_dynamic_check_t` and improve compilation times. + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + shall_we_copy_t::value, + boost::mpl::identity >, + boost::mpl::if_< + shall_we_copy_with_dynamic_check_t, + boost::detail::dynamic_num_converter_impl, + boost::detail::lexical_converter_impl + > + >::type caster_type_lazy; - typedef BOOST_DEDUCED_TYPENAME caster_type_lazy::type caster_type; + typedef BOOST_DEDUCED_TYPENAME caster_type_lazy::type caster_type; - return caster_type::try_convert(static_cast(arg), result); + return caster_type::try_convert(static_cast(arg), result); + } + + template + inline bool try_lexical_convert(const CharacterT* chars, std::size_t count, Target& result) + { + BOOST_STATIC_ASSERT_MSG( + boost::detail::is_character::value, + "This overload of try_lexical_convert is meant to be used only with arrays of characters." + ); + return ::boost::conversion::detail::try_lexical_convert( + ::boost::iterator_range(chars, chars + count), result + ); + } + + }} // namespace conversion::detail + + namespace conversion { + // ADL barrier + using ::boost::conversion::detail::try_lexical_convert; } template @@ -2320,7 +2325,7 @@ namespace boost { { Target result; - if (!try_lexical_convert(arg, result)) + if (!boost::conversion::detail::try_lexical_convert(arg, result)) BOOST_LCAST_THROW_BAD_CAST(Source, Target); return result; @@ -2334,27 +2339,11 @@ namespace boost { ); } - template - inline bool try_lexical_convert(const char* chars, std::size_t count, Target& result) - { - return ::boost::try_lexical_convert( - ::boost::iterator_range(chars, chars + count), result - ); - } - template inline Target lexical_cast(const unsigned char* chars, std::size_t count) { - return ::boost::lexical_cast( + return ::boost::lexical_cast( ::boost::iterator_range(chars, chars + count) - ); - } - - template - inline bool try_lexical_convert(const unsigned char* chars, std::size_t count, Target& result) - { - return ::boost::try_lexical_convert( - ::boost::iterator_range(chars, chars + count), result ); } @@ -2366,14 +2355,6 @@ namespace boost { ); } - template - inline bool try_lexical_convert(const signed char* chars, std::size_t count, Target& result) - { - return ::boost::try_lexical_convert( - ::boost::iterator_range(chars, chars + count), result - ); - } - #ifndef BOOST_LCAST_NO_WCHAR_T template inline Target lexical_cast(const wchar_t* chars, std::size_t count) @@ -2382,14 +2363,6 @@ namespace boost { ::boost::iterator_range(chars, chars + count) ); } - - template - inline bool try_lexical_convert(const wchar_t* chars, std::size_t count, Target& result) - { - return ::boost::try_lexical_convert( - ::boost::iterator_range(chars, chars + count), result - ); - } #endif #ifndef BOOST_NO_CXX11_CHAR16_T template @@ -2399,14 +2372,6 @@ namespace boost { ::boost::iterator_range(chars, chars + count) ); } - - template - inline bool try_lexical_convert(const char16_t* chars, std::size_t count, Target& result) - { - return ::boost::try_lexical_convert( - ::boost::iterator_range(chars, chars + count), result - ); - } #endif #ifndef BOOST_NO_CXX11_CHAR32_T template @@ -2416,14 +2381,6 @@ namespace boost { ::boost::iterator_range(chars, chars + count) ); } - - template - inline bool try_lexical_convert(const char32_t* chars, std::size_t count, Target& result) - { - return ::boost::try_lexical_convert( - ::boost::iterator_range(chars, chars + count), result - ); - } #endif } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1ac10ae..3acf6b4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -62,6 +62,7 @@ test-suite conversion [ run lexical_cast_stream_traits_test.cpp ] [ compile-fail lexical_cast_to_pointer_test.cpp ] [ run lexical_cast_filesystem_test.cpp ../../filesystem/build//boost_filesystem/static ] + [ run lexical_cast_try_lexical_convert.cpp ] ; # Assuring that examples compile and run. Adding sources from `example` directory to the `conversion` test suite. diff --git a/test/lexical_cast_try_lexical_convert.cpp b/test/lexical_cast_try_lexical_convert.cpp new file mode 100644 index 0000000..0c7c4de --- /dev/null +++ b/test/lexical_cast_try_lexical_convert.cpp @@ -0,0 +1,78 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2014. +// +// 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 + +#include +#include + +using namespace boost; + +void try_uncommon_cases() +{ + std::string sres; + const bool res1 = conversion::try_lexical_convert(std::string("Test string"), sres); + BOOST_CHECK(res1); + BOOST_CHECK_EQUAL(sres, "Test string"); + + volatile int vires; + const bool res2 = conversion::try_lexical_convert(100, vires); + BOOST_CHECK(res2); + BOOST_CHECK_EQUAL(vires, 100); + + const bool res3 = conversion::try_lexical_convert("Test string", sres); + BOOST_CHECK(res3); + BOOST_CHECK_EQUAL(sres, "Test string"); + + const bool res4 = conversion::try_lexical_convert("Test string", sizeof("Test string") - 1, sres); + BOOST_CHECK(res4); + BOOST_CHECK_EQUAL(sres, "Test string"); + + int ires; + BOOST_CHECK(!conversion::try_lexical_convert("Test string", ires)); + BOOST_CHECK(!conversion::try_lexical_convert(1.1, ires)); + BOOST_CHECK(!conversion::try_lexical_convert(-1.9, ires)); + BOOST_CHECK(!conversion::try_lexical_convert("1.1", ires)); + BOOST_CHECK(!conversion::try_lexical_convert("1000000000000000000000000000000000000000", ires)); +} + + +void try_common_cases() +{ + int ires = 0; + const bool res1 = conversion::try_lexical_convert(std::string("100"), ires); + BOOST_CHECK(res1); + BOOST_CHECK_EQUAL(ires, 100); + + ires = 0; + const bool res2 = conversion::try_lexical_convert("-100", ires); + BOOST_CHECK(res2); + BOOST_CHECK_EQUAL(ires, -100); + + float fres = 1.0f; + const bool res3 = conversion::try_lexical_convert("0.0", fres); + BOOST_CHECK(res3); + BOOST_CHECK_EQUAL(fres, 0.0f); + + fres = 1.0f; + const bool res4 = conversion::try_lexical_convert("0.0", sizeof("0.0") - 1, fres); + BOOST_CHECK(res4); + BOOST_CHECK_EQUAL(fres, 0.0f); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("Tests for try_lexical_convert"); + suite->add(BOOST_TEST_CASE(&try_uncommon_cases)); + suite->add(BOOST_TEST_CASE(&try_common_cases)); + + return suite; +}