diff --git a/include/boost/json/detail/value_from.hpp b/include/boost/json/detail/value_from.hpp index a8763eeb..4fe74b5f 100644 --- a/include/boost/json/detail/value_from.hpp +++ b/include/boost/json/detail/value_from.hpp @@ -119,7 +119,9 @@ value_from_helper( result.reserve(detail::try_size(from, size_implementation())); for (auto&& elem : from) result.emplace_back( - value_from(elem, result.storage())); + value_from( + static_cast< forwarded_value >(elem), + result.storage() )); } // tuple-like types diff --git a/include/boost/json/impl/conversion.hpp b/include/boost/json/impl/conversion.hpp index 8e0b6abc..f31fb094 100644 --- a/include/boost/json/impl/conversion.hpp +++ b/include/boost/json/impl/conversion.hpp @@ -37,8 +37,12 @@ template using tuple_element_t = typename std::tuple_element::type; template -using value_type = typename std::iterator_traits()) )>::value_type; +using iterator_type = decltype(std::begin(std::declval())); +template +using iterator_traits = std::iterator_traits< iterator_type >; + +template +using value_type = typename iterator_traits::value_type; template using mapped_type = tuple_element_t< 1, value_type >; @@ -52,8 +56,6 @@ using key_type = mp11::mp_eval_or< key_type_helper, T>; -template -using iterator_type = decltype(std::begin(std::declval())); template using are_begin_and_end_same = std::is_same< iterator_type, @@ -219,6 +221,43 @@ template using conversion_round_trips = conversion_round_trips_helper< conversion_implementation, conversion_implementation>>; + +template< class T1, class T2 > +struct copy_cref_helper +{ + using type = remove_cvref; +}; +template< class T1, class T2 > +using copy_cref = typename copy_cref_helper< T1, T2 >::type; + +template< class T1, class T2 > +struct copy_cref_helper +{ + using type = remove_cvref const; +}; +template< class T1, class T2 > +struct copy_cref_helper +{ + using type = copy_cref&; +}; +template< class T1, class T2 > +struct copy_cref_helper +{ + using type = copy_cref&&; +}; + +template< class Rng, class Traits > +using forwarded_value_helper = mp11::mp_if< + std::is_convertible< + typename Traits::reference, + copy_cref >, + copy_cref, + typename Traits::value_type >; + +template< class Rng > +using forwarded_value = forwarded_value_helper< + Rng, iterator_traits< Rng > >; + } // namespace detail template diff --git a/test/conversion.cpp b/test/conversion.cpp index cd3fd1e5..8e9369fb 100644 --- a/test/conversion.cpp +++ b/test/conversion.cpp @@ -194,6 +194,23 @@ public: BOOST_STATIC_ASSERT( !is_described_enum::value ); BOOST_STATIC_ASSERT( !is_described_enum::value ); #endif + + BOOST_STATIC_ASSERT( + std::is_same< + detail::forwarded_value< std::vector& >, + int& >::value ); + BOOST_STATIC_ASSERT( + std::is_same< + detail::forwarded_value< std::vector const& >, + int const& >::value ); + BOOST_STATIC_ASSERT( + std::is_same< + detail::forwarded_value< std::vector&& >, + int >::value ); + BOOST_STATIC_ASSERT( + std::is_same< + detail::forwarded_value< std::vector& >, + bool >::value ); } }; diff --git a/test/value_to.cpp b/test/value_to.cpp index aa7767ea..aa7f86ab 100644 --- a/test/value_to.cpp +++ b/test/value_to.cpp @@ -219,6 +219,7 @@ public: { "a", 1 }, {"b", 2}, {"c", 3} }); check(std::vector{1, 2, 3, 4}); + check(std::vector{true, false, false, true}); check(std::make_pair(std::string("test"), 5)); check(std::make_tuple(std::string("outer"), std::make_pair(std::string("test"), 5)));