diff --git a/include/boost/iterator/detail/operator_brackets_dispatch.hpp b/include/boost/iterator/detail/operator_brackets_dispatch.hpp new file mode 100644 index 0000000..fdbd929 --- /dev/null +++ b/include/boost/iterator/detail/operator_brackets_dispatch.hpp @@ -0,0 +1,88 @@ +// (C) Copyright David Abrahams 2002. +// (C) Copyright Jeremy Siek 2002. +// (C) Copyright Thomas Witt 2002. +// (C) Copyright Jeffrey Lee Hellrung, Jr. 2012. +// 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) +#ifndef BOOST_OPERATOR_BRACKETS_DISPATCH_07102012JLH_HPP +#define BOOST_OPERATOR_BRACKETS_DISPATCH_07102012JLH_HPP + +#include + +#include +#include + +#include + +namespace boost { namespace detail { + +// operator[] must return a proxy in case iterator destruction invalidates +// referents. +// To see why, consider the following implementation of operator[]: +// reference operator[](difference_type n) const +// { return *(*this + n); } +// The problem here is that operator[] would return a reference created from +// a temporary iterator. + +template +struct operator_brackets_value +{ + typedef Value result_type; + template + static result_type apply(Iterator const & i) + { return *i; } +}; + +template +struct operator_brackets_const_proxy +{ + class result_type + { + Iterator const m_i; + explicit result_type(Iterator const & i) : m_i(i) { } + friend struct operator_brackets_const_proxy; + void operator=(result_type&); + public: + operator Reference() const { return *m_i; } + }; + static result_type apply(Iterator const & i) + { return result_type(i); } +}; + +template +struct operator_brackets_proxy +{ + class result_type + { + Iterator const m_i; + explicit result_type(Iterator const & i) : m_i(i) { } + friend struct operator_brackets_proxy; + void operator=(result_type&); + public: + operator Reference() const { return *m_i; } + operator_brackets_proxy const & operator=( + typename Iterator::value_type const & x) const + { *m_i = x; return *this; } + }; + static result_type apply(Iterator const & i) + { return result_type(i); } +}; + +template +struct operator_brackets_dispatch +{ + typedef typename mpl::if_c< + iterator_writability_disabled::value, + typename mpl::if_c< + boost::is_POD::value, + operator_brackets_value::type>, + operator_brackets_const_proxy + >::type, + operator_brackets_proxy + >::type type; +}; + +} } // namespace detail / namespace boost + +#endif // #ifndef BOOST_OPERATOR_BRACKETS_DISPATCH_07102012JLH_HPP diff --git a/include/boost/iterator/iterator_facade.hpp b/include/boost/iterator/iterator_facade.hpp index d84b402..6f55692 100644 --- a/include/boost/iterator/iterator_facade.hpp +++ b/include/boost/iterator/iterator_facade.hpp @@ -1,6 +1,7 @@ // (C) Copyright David Abrahams 2002. // (C) Copyright Jeremy Siek 2002. // (C) Copyright Thomas Witt 2002. +// (C) copyright Jeffrey Lee Hellrung, Jr. 2012. // 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) @@ -13,6 +14,7 @@ #include #include +#include #include #include @@ -75,7 +77,7 @@ namespace boost , Return , int[3] >::type type; - }; + }; #else : ::boost::iterators::enable_if< mpl::or_< @@ -85,7 +87,7 @@ namespace boost , Return > {}; -#endif +#endif // // Generates associated types for an iterator_facade with the @@ -94,7 +96,7 @@ namespace boost template < class ValueParam , class CategoryOrTraversal - , class Reference + , class Reference , class Difference > struct iterator_facade_types @@ -102,16 +104,16 @@ namespace boost typedef typename facade_iterator_category< CategoryOrTraversal, ValueParam, Reference >::type iterator_category; - + typedef typename remove_const::type value_type; - + // Not the real associated pointer type typedef typename mpl::eval_if< boost::detail::iterator_writability_disabled , add_pointer , add_pointer >::type pointer; - + # if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ && (BOOST_WORKAROUND(_STLPORT_VERSION, BOOST_TESTED_AT(0x452)) \ || BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, BOOST_TESTED_AT(310))) \ @@ -157,7 +159,7 @@ namespace boost private: mutable value_type stored_value; }; - + // // In general, we can't determine that such an iterator isn't // writable -- we also need to store a copy of the old iterator so @@ -209,7 +211,7 @@ namespace boost { return stored_iterator; } - + private: mutable value_type stored_value; Iterator stored_iterator; @@ -221,7 +223,7 @@ namespace boost struct is_non_proxy_reference_impl { static Reference r; - + template static typename mpl::if_< is_convertible< @@ -231,17 +233,17 @@ namespace boost , char[1] , char[2] >::type& helper(R const&); - + BOOST_STATIC_CONSTANT(bool, value = sizeof(helper(r)) == 1); }; - + template struct is_non_proxy_reference : mpl::bool_< is_non_proxy_reference_impl::value > {}; -# else +# else template struct is_non_proxy_reference : is_convertible< @@ -250,8 +252,8 @@ namespace boost , Value const volatile* > {}; -# endif - +# endif + // A metafunction to choose the result type of postfix ++ // // Because the C++98 input iterator requirements say that *r++ has @@ -273,7 +275,7 @@ namespace boost mpl::and_< // A proxy is only needed for readable iterators is_convertible - + // No multipass iterator can have values that disappear // before positions can be re-visited , mpl::not_< @@ -296,7 +298,7 @@ namespace boost // standard's requirements. If *i is not a reference type, we must still // produce an lvalue to which a pointer can be formed. We do that by // returning a proxy object containing an instance of the reference object. - template + template struct operator_arrow_dispatch // proxy references { struct proxy @@ -315,10 +317,10 @@ namespace boost } }; - template - struct operator_arrow_dispatch // "real" references + template + struct operator_arrow_dispatch // "real" references { - typedef Pointer result_type; + typedef T* result_type; static result_type apply(T& x) { return boost::addressof(x); @@ -328,79 +330,12 @@ namespace boost # if BOOST_WORKAROUND(BOOST_MSVC, < 1300) // Deal with ETI template<> - struct operator_arrow_dispatch + struct operator_arrow_dispatch { typedef int result_type; }; # endif - // A proxy return type for operator[], needed to deal with - // iterators that may invalidate referents upon destruction. - // Consider the temporary iterator in *(a + n) - template - class operator_brackets_proxy - { - // Iterator is actually an iterator_facade, so we do not have to - // go through iterator_traits to access the traits. - typedef typename Iterator::reference reference; - typedef typename Iterator::value_type value_type; - - public: - operator_brackets_proxy(Iterator const& iter) - : m_iter(iter) - {} - - operator reference() const - { - return *m_iter; - } - - operator_brackets_proxy& operator=(value_type const& val) - { - *m_iter = val; - return *this; - } - - private: - Iterator m_iter; - }; - - // A metafunction that determines whether operator[] must return a - // proxy, or whether it can simply return a copy of the value_type. - template - struct use_operator_brackets_proxy - : mpl::not_< - mpl::and_< - // Really we want an is_copy_constructible trait here, - // but is_POD will have to suffice in the meantime. - boost::is_POD - , iterator_writability_disabled - > - > - {}; - - template - struct operator_brackets_result - { - typedef typename mpl::if_< - use_operator_brackets_proxy - , operator_brackets_proxy - , Value - >::type type; - }; - - template - operator_brackets_proxy make_operator_brackets_result(Iterator const& iter, mpl::true_) - { - return operator_brackets_proxy(iter); - } - - template - typename Iterator::value_type make_operator_brackets_result(Iterator const& iter, mpl::false_) - { - return *iter; - } - struct choose_difference_type { template @@ -414,13 +349,13 @@ namespace boost , typename I1::difference_type , typename I2::difference_type > -# else +# else mpl::eval_if< is_convertible , iterator_difference , iterator_difference > -# endif +# endif {}; }; @@ -438,7 +373,7 @@ namespace boost operator op( \ iterator_facade const& lhs \ , iterator_facade const& rhs) -# else +# else # define BOOST_ITERATOR_FACADE_INTEROP_HEAD(prefix, op, result_type) \ template < \ class Derived1, class V1, class TC1, class Reference1, class Difference1 \ @@ -451,7 +386,7 @@ namespace boost operator op( \ iterator_facade const& lhs \ , iterator_facade const& rhs) -# endif +# endif # define BOOST_ITERATOR_FACADE_PLUS_HEAD(prefix,args) \ template \ @@ -468,12 +403,12 @@ namespace boost // class iterator_core_access { -# if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) +# if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. public: # else - + template friend class iterator_facade; # define BOOST_ITERATOR_FACADE_RELATION(op) \ @@ -616,14 +551,15 @@ namespace boost > associated_types; typedef boost::detail::operator_arrow_dispatch< - Reference - , typename associated_types::pointer - > operator_arrow_dispatch_; + Reference> operator_arrow_dispatch_; + + typedef typename boost::detail::operator_brackets_dispatch< + Derived, Value, Reference>::type operator_brackets_dispatch_; protected: // For use by derived classes typedef iterator_facade iterator_facade_; - + public: typedef typename associated_types::value_type value_type; @@ -643,16 +579,11 @@ namespace boost { return operator_arrow_dispatch_::apply(*this->derived()); } - - typename boost::detail::operator_brackets_result::type + + typename operator_brackets_dispatch_::result_type operator[](difference_type n) const { - typedef boost::detail::use_operator_brackets_proxy use_proxy; - - return boost::detail::make_operator_brackets_result( - this->derived() + n - , use_proxy() - ); + return operator_brackets_dispatch_::apply(this->derived() + n); } Derived& operator++() @@ -671,7 +602,7 @@ namespace boost return tmp; } # endif - + Derived& operator--() { iterator_core_access::decrement(this->derived()); @@ -726,14 +657,14 @@ namespace boost { typename boost::detail::postfix_increment_result::type tmp(*static_cast(&i)); - + ++i; - + return tmp; } -# endif +# endif + - // // Comparison operator implementation. The library supplied operators // enables the user to provide fully interoperable constant/mutable diff --git a/test/indirect_iter_member_types.cpp b/test/indirect_iter_member_types.cpp index 84dcaeb..c2a52fb 100644 --- a/test/indirect_iter_member_types.cpp +++ b/test/indirect_iter_member_types.cpp @@ -82,7 +82,7 @@ int main() typedef boost::indirect_iterator Iter; STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::reference, long&); - STATIC_ASSERT_SAME(Iter::pointer, int*); + STATIC_ASSERT_SAME(Iter::pointer, long*); STATIC_ASSERT_SAME(Iter::difference_type, short); } return 0;