From 79d2a66831af16f29befaa4d32461928b9431a15 Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Sun, 2 Mar 2014 15:35:50 +0000 Subject: [PATCH] trac 5816 - fix any_range requiring copyable elements. --- .../range/detail/any_iterator_interface.hpp | 29 +++++++--- .../range/detail/any_iterator_wrapper.hpp | 54 +++++++++++++++--- test/adaptor_test/type_erased.cpp | 55 +++++++++++++++++++ 3 files changed, 123 insertions(+), 15 deletions(-) diff --git a/include/boost/range/detail/any_iterator_interface.hpp b/include/boost/range/detail/any_iterator_interface.hpp index 2451491..cd56714 100644 --- a/include/boost/range/detail/any_iterator_interface.hpp +++ b/include/boost/range/detail/any_iterator_interface.hpp @@ -27,25 +27,40 @@ namespace boost { typedef typename mpl::if_< typename is_reference::type, - typename add_reference< - typename add_const< - typename remove_reference::type - >::type - >::type, + typename add_const< + typename remove_reference::type + >::type&, T >::type type; }; + template + struct mutable_reference_type_generator + { + typedef typename mpl::if_< + typename mpl::and_< + typename is_const::type, + typename mpl::not_::type>::type + >::type, + T, + typename add_reference::type + >::type type; + }; + template< class Reference , class Buffer > struct any_incrementable_iterator_interface { - typedef Reference reference; + typedef typename mutable_reference_type_generator< + Reference + >::type reference; + typedef typename const_reference_type_generator< Reference >::type const_reference; + typedef typename remove_const< typename remove_reference::type >::type reference_as_value_type; @@ -87,7 +102,7 @@ namespace boost virtual any_single_pass_iterator_interface* clone_reference_as_value(buffer_type& buffer) const = 0; - virtual Reference dereference() const = 0; + virtual reference dereference() const = 0; virtual bool equal(const any_single_pass_iterator_interface& other) const = 0; }; diff --git a/include/boost/range/detail/any_iterator_wrapper.hpp b/include/boost/range/detail/any_iterator_wrapper.hpp index 502e3e8..2526aa8 100644 --- a/include/boost/range/detail/any_iterator_wrapper.hpp +++ b/include/boost/range/detail/any_iterator_wrapper.hpp @@ -19,6 +19,17 @@ namespace boost { namespace range_detail { + template + Reference dereference_cast(T& x) + { + return static_cast(x); + } + template + Reference dereference_cast(const T& x) + { + return static_cast(const_cast(x)); + } + template< class WrappedIterator , class Reference @@ -114,7 +125,13 @@ namespace boost { struct disabler {}; BOOST_RANGE_CONCEPT_ASSERT(( SinglePassIteratorConcept )); + typedef any_single_pass_iterator_interface< + Reference, + Buffer + > base_type; + public: + typedef typename base_type::reference reference; any_single_pass_iterator_wrapper() : m_it() @@ -178,9 +195,9 @@ namespace boost return m_it == boost::polymorphic_downcast(&other)->m_it; } - virtual Reference dereference() const + virtual reference dereference() const { - return *m_it; + return dereference_cast(*m_it); } private: @@ -199,7 +216,14 @@ namespace boost > { BOOST_RANGE_CONCEPT_ASSERT(( ForwardIteratorConcept )); + typedef any_forward_iterator_interface< + Reference, + Buffer + > base_type; + public: + typedef typename base_type::reference reference; + any_forward_iterator_wrapper() : m_it() {} @@ -263,9 +287,9 @@ namespace boost return m_it == boost::polymorphic_downcast(&other)->m_it; } - virtual Reference dereference() const + virtual reference dereference() const { - return *m_it; + return dereference_cast(*m_it); } private: WrappedIterator m_it; @@ -283,7 +307,14 @@ namespace boost > { BOOST_RANGE_CONCEPT_ASSERT(( BidirectionalIteratorConcept )); + typedef any_bidirectional_iterator_interface< + Reference, + Buffer + > base_type; + public: + typedef typename base_type::reference reference; + any_bidirectional_iterator_wrapper() : m_it() { @@ -353,9 +384,9 @@ namespace boost return m_it == boost::polymorphic_downcast(&other)->m_it; } - virtual Reference dereference() const + virtual reference dereference() const { - return *m_it; + return dereference_cast(*m_it); } private: @@ -376,7 +407,14 @@ namespace boost > { BOOST_RANGE_CONCEPT_ASSERT(( RandomAccessIteratorConcept )); + typedef any_random_access_iterator_interface< + Reference, + Difference, + Buffer + > base_type; + public: + typedef typename base_type::reference reference; typedef Difference difference_type; any_random_access_iterator_wrapper() @@ -457,9 +495,9 @@ namespace boost m_it += offset; } - virtual Reference dereference() const + virtual reference dereference() const { - return *m_it; + return dereference_cast(*m_it); } virtual Difference distance_to(const any_random_access_iterator_interface& other) const diff --git a/test/adaptor_test/type_erased.cpp b/test/adaptor_test/type_erased.cpp index a3693dc..801fec6 100644 --- a/test/adaptor_test/type_erased.cpp +++ b/test/adaptor_test/type_erased.cpp @@ -476,6 +476,60 @@ namespace boost_range_adaptor_type_erased_test BOOST_CHECK_EQUAL( rng[i], i ); } } + + class dummy_interface + { + public: + virtual ~dummy_interface() { } + virtual void test() = 0; + protected: + dummy_interface() { } + private: + dummy_interface(const dummy_interface&); + void operator=(const dummy_interface&); + }; + + class dummy_impl + : public dummy_interface + { + public: + dummy_impl() { } + dummy_impl(const dummy_impl&) { } + dummy_impl& operator=(const dummy_impl&) { return *this; } + virtual void test() { } + }; + + typedef boost::any_range< + dummy_interface, + boost::random_access_traversal_tag, + dummy_interface&, + std::ptrdiff_t + > any_interface_range; + + struct foo_dummy_interface_fn + { + void operator()(dummy_interface& iface) + { + iface.test(); + } + }; + + void foo_test_dummy_interface_range(any_interface_range rng) + { + std::for_each(boost::begin(rng), boost::end(rng), + foo_dummy_interface_fn()); + } + + void test_type_erased_abstract() + { + std::vector v(10); + + any_interface_range r(v); + + foo_test_dummy_interface_range(r); + + foo_test_dummy_interface_range(any_interface_range(v)); + } } boost::unit_test::test_suite* @@ -492,6 +546,7 @@ init_unit_test_suite(int argc, char* argv[]) test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_multiple_different_template_parameter_conversion ) ); test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_mix_values ) ); test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_operator_brackets ) ); + test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_abstract ) ); return test; }