diff --git a/include/boost/iterator/iterator_facade.hpp b/include/boost/iterator/iterator_facade.hpp index b43e618..20cde3d 100644 --- a/include/boost/iterator/iterator_facade.hpp +++ b/include/boost/iterator/iterator_facade.hpp @@ -150,72 +150,54 @@ namespace iterators { // value must be read and stored away before the increment occurs // so that *a++ yields the originally referenced element and not // the next one. + template + class postfix_increment_dereference_proxy + { + typedef Value value_type; + public: +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + explicit postfix_increment_dereference_proxy(OtherValue&& x) + : stored_value(static_cast< OtherValue&& >(x)) + {} +#else + explicit postfix_increment_dereference_proxy(value_type const& x) + : stored_value(x) + {} + + explicit postfix_increment_dereference_proxy(value_type& x) + : stored_value(x) + {} +#endif + + // Returning a mutable reference allows nonsense like + // (*r++).mutate(), but it imposes fewer assumptions about the + // behavior of the value_type. In particular, recall that + // (*r).mutate() is legal if operator* returns by value. + // Provides readability of *r++ + operator value_type&() const + { + return this->stored_value; + } + + private: + mutable value_type stored_value; + }; + template class postfix_increment_proxy { typedef typename iterator_value::type value_type; public: explicit postfix_increment_proxy(Iterator const& x) - : stored_value(*x) + : stored_iterator(x) + , dereference_proxy(*x) {} - // Returning a mutable reference allows nonsense like - // (*r++).mutate(), but it imposes fewer assumptions about the - // behavior of the value_type. In particular, recall that - // (*r).mutate() is legal if operator* returns by value. - value_type& + postfix_increment_dereference_proxy const& operator*() const { - return this->stored_value; - } - 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 - // that it can be written into. - template - class writable_postfix_increment_proxy - { - typedef typename iterator_value::type value_type; - public: - explicit writable_postfix_increment_proxy(Iterator const& x) - : stored_value(*x) - , stored_iterator(x) - {} - - // Dereferencing must return a proxy so that both *r++ = o and - // value_type(*r++) can work. In this case, *r is the same as - // *r++, and the conversion operator below is used to ensure - // readability. - writable_postfix_increment_proxy const& - operator*() const - { - return *this; - } - - // Provides readability of *r++ - operator value_type&() const - { - return stored_value; - } - - // Provides writability of *r++ - template - T const& operator=(T const& x) const - { - *this->stored_iterator = x; - return x; - } - - // This overload just in case only non-const objects are writable - template - T& operator=(T& x) const - { - *this->stored_iterator = x; - return x; + return dereference_proxy; } // Provides X(r++) @@ -225,8 +207,122 @@ namespace iterators { } private: - mutable value_type stored_value; Iterator stored_iterator; + postfix_increment_dereference_proxy dereference_proxy; + }; + + + template + class writable_postfix_increment_dereference_proxy; + + template + struct is_not_writable_postfix_increment_dereference_proxy : + public boost::true_type + {}; + + template + struct is_not_writable_postfix_increment_dereference_proxy< + writable_postfix_increment_dereference_proxy + > : + public boost::false_type + {}; + + template + class writable_postfix_increment_proxy; + + // + // 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 + // that it can be written into. + template + class writable_postfix_increment_dereference_proxy + { + friend class writable_postfix_increment_proxy; + + typedef typename iterator_value::type value_type; + + public: + explicit writable_postfix_increment_dereference_proxy(Iterator const& x) + : stored_iterator(x) + , stored_value(*x) + {} + + // Provides readability of *r++ + operator value_type&() const + { + return this->stored_value; + } + + template + writable_postfix_increment_dereference_proxy const& + operator=(writable_postfix_increment_dereference_proxy const& x) const + { + typedef typename iterator_value::type other_value_type; + *this->stored_iterator = static_cast(x); + return *this; + } + + // Provides writability of *r++ +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + typename iterators::enable_if< + is_not_writable_postfix_increment_dereference_proxy< T >, + writable_postfix_increment_dereference_proxy const& + >::type operator=(T&& x) const + { + *this->stored_iterator = static_cast< T&& >(x); + return *this; + } +#else + template + typename iterators::enable_if< + is_not_writable_postfix_increment_dereference_proxy< T >, + writable_postfix_increment_dereference_proxy const& + >::type operator=(T const& x) const + { + *this->stored_iterator = x; + return *this; + } + + // This overload just in case only non-const objects are writable + template + typename iterators::enable_if< + is_not_writable_postfix_increment_dereference_proxy< T >, + writable_postfix_increment_dereference_proxy const& + >::type operator=(T& x) const + { + *this->stored_iterator = x; + return *this; + } +#endif + + private: + Iterator stored_iterator; + mutable value_type stored_value; + }; + + template + class writable_postfix_increment_proxy + { + public: + explicit writable_postfix_increment_proxy(Iterator const& x) + : dereference_proxy(x) + {} + + writable_postfix_increment_dereference_proxy const& + operator*() const + { + return dereference_proxy; + } + + // Provides X(r++) + operator Iterator const&() const + { + return dereference_proxy.stored_iterator; + } + + private: + writable_postfix_increment_dereference_proxy dereference_proxy; }; # ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION