diff --git a/doc/iterator_facade_body.rst b/doc/iterator_facade_body.rst index 25a389c..370539d 100644 --- a/doc/iterator_facade_body.rst +++ b/doc/iterator_facade_body.rst @@ -151,14 +151,16 @@ into the temporary iterator ``p+n``, which is destroyed when Writable iterators built with ``iterator_facade`` implement the semantics required by the preferred resolution to `issue 299`_ and -adopted by proposal n1550_: the result of ``p[n]`` is a proxy object -containing a copy of ``p+n``, and ``p[n] = x`` is equivalent to ``*(p -+ n) = x``. This approach will work properly for any random-access -iterator regardless of the other details of its implementation. A -user who knows more about the implementation of her iterator is free -to implement an ``operator[]`` which returns an lvalue in the derived -iterator class; it will hide the one supplied by ``iterator_facade`` -from clients of her iterator. +adopted by proposal n1550_: the result of ``p[n]`` is an object +convertible to the iterator's ``value_type``, and ``p[n] = x`` is +equivalent to ``*(p + n) = x`` (Note: This result object may be +implemented as a proxy containing a copy of ``p+n``). This approach +will work properly for any random-access iterator regardless of the +other details of its implementation. A user who knows more about +the implementation of her iterator is free to implement an +``operator[]`` that returns an lvalue in the derived iterator +class; it will hide the one supplied by ``iterator_facade`` from +clients of her iterator. .. _n1550: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/n1550.html diff --git a/doc/iterator_facade_ref.rst b/doc/iterator_facade_ref.rst index dbec7d1..c763573 100644 --- a/doc/iterator_facade_ref.rst +++ b/doc/iterator_facade_ref.rst @@ -245,10 +245,13 @@ __ `operator arrow`_ *unspecified* ``operator[](difference_type n) const;`` -:Returns: an object convertible to ``reference`` and holding a copy - *p* of ``*static_cast(this) + n`` such that, for a constant object ``v`` of type - ``value_type``, ``(*static_cast(this))[n] = v`` is equivalent - to ``p = v``. +:Returns: an object convertible to ``value_type``. For constant + objects ``v`` of type ``value_type``, and ``n`` of type + ``difference_type``, and reference ``p`` equal to + ``*static_cast(this)``, ``(*this)[n] = v`` is + equivalent to ``*(p+ n) = v``, and ``static_cast((*this)[n])`` is equivalent to + ``static_cast(*(p+n))`` diff --git a/include/boost/iterator/iterator_facade.hpp b/include/boost/iterator/iterator_facade.hpp index 79b2d3c..68a5c71 100644 --- a/include/boost/iterator/iterator_facade.hpp +++ b/include/boost/iterator/iterator_facade.hpp @@ -22,9 +22,11 @@ #include #include #include +#include #include #include +#include #include // this goes last @@ -182,11 +184,21 @@ namespace boost Iterator m_iter; }; + template + struct use_operator_brackets_proxy + : 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_< - iterator_writability_disabled + use_operator_brackets_proxy , Value , operator_brackets_proxy >::type type; @@ -387,12 +399,11 @@ namespace boost typename detail::operator_brackets_result::type operator[](difference_type n) const { - typedef detail::iterator_writability_disabled - not_writable; + typedef detail::use_operator_brackets_proxy use_proxy; return detail::make_operator_brackets_result( this->derived() + n - , not_writable() + , use_proxy() ); } diff --git a/include/boost/pointee.hpp b/include/boost/pointee.hpp index 5c40a0f..d4339b9 100755 --- a/include/boost/pointee.hpp +++ b/include/boost/pointee.hpp @@ -9,7 +9,9 @@ # include # include +# include # include +# include # include namespace boost { @@ -17,9 +19,37 @@ namespace boost { namespace detail { template - struct smart_ptr_value + struct smart_ptr_pointee { - typedef typename remove_cv::type type; + typedef typename P::element_type type; + }; + + template + struct iterator_pointee + { + typedef typename iterator_traits::value_type value_type; + + struct impl + { + template + static char test(T const&); + + static char (& test(value_type&) )[2]; + + static Iterator& x; + }; + + BOOST_STATIC_CONSTANT(bool, is_constant = sizeof(impl::test(*impl::x)) == 1); + + typedef typename mpl::if_c< +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) + ::boost::detail::iterator_pointee::is_constant +# else + is_constant +# endif + , typename add_const::type + , value_type + >::type type; }; } @@ -27,11 +57,11 @@ template struct pointee { typedef typename remove_cv

::type stripped; - + typedef typename mpl::apply_if< detail::is_incrementable - , iterator_value - , detail::smart_ptr_value + , detail::iterator_pointee + , detail::smart_ptr_pointee >::type type; }; diff --git a/test/Jamfile b/test/Jamfile index 1cd2c81..b5629e4 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -29,6 +29,7 @@ test-suite iterator # These tests should work for just about everything. [ compile is_lvalue_iterator.cpp ] [ compile is_readable_iterator.cpp ] + [ compile pointee.cpp ] [ run unit_tests.cpp ] [ run concept_tests.cpp ] diff --git a/test/indirect_iterator_member_types.cpp b/test/indirect_iterator_member_types.cpp index 55bff61..b4013ad 100644 --- a/test/indirect_iterator_member_types.cpp +++ b/test/indirect_iterator_member_types.cpp @@ -30,19 +30,8 @@ struct my_ptr { BOOST_TT_BROKEN_COMPILER_SPEC(my_ptr) BOOST_TT_BROKEN_COMPILER_SPEC(zow) -#ifndef BOOST_ITERATOR_REF_CONSTNESS_KILLS_WRITABILITY - -# define STATIC_ASSERT_SAME_POINTER(P1, P2) \ - STATIC_ASSERT_SAME( \ - boost::remove_const::type>::type \ - , boost::remove_const::type>::type \ - ) - -#else - -# define STATIC_ASSERT_SAME_POINTER(P1, P2) STATIC_ASSERT_SAME(P1,P2) - -#endif +// Borland 5.6.4 and earlier drop const all over the place, so this +// test will fail in the lines marked with (**) int main() { @@ -50,7 +39,7 @@ int main() typedef boost::indirect_iterator Iter; STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::reference, int&); - STATIC_ASSERT_SAME_POINTER(Iter::pointer, int*); + STATIC_ASSERT_SAME(Iter::pointer, int*); STATIC_ASSERT_SAME(Iter::difference_type, std::ptrdiff_t); BOOST_STATIC_ASSERT((boost::is_convertible Iter; STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::reference, const int&); -#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland drops const all over the place - STATIC_ASSERT_SAME_POINTER(Iter::pointer, const int*); -#endif + STATIC_ASSERT_SAME(Iter::pointer, const int*); // (**) } { typedef boost::indirect_iterator Iter; STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::reference, int&); - STATIC_ASSERT_SAME_POINTER(Iter::pointer, int*); + STATIC_ASSERT_SAME(Iter::pointer, int*); } { typedef boost::indirect_iterator Iter; STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::reference, const int&); -#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland drops const all over the place - STATIC_ASSERT_SAME_POINTER(Iter::pointer, const int*); -#endif + STATIC_ASSERT_SAME(Iter::pointer, const int*); // (**) } { typedef boost::indirect_iterator Iter; STATIC_ASSERT_SAME(Iter::value_type, zow); -#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland drops const all over the place - STATIC_ASSERT_SAME(Iter::reference, const zow&); - STATIC_ASSERT_SAME_POINTER(Iter::pointer, const zow*); -#endif + STATIC_ASSERT_SAME(Iter::reference, const zow&); // (**) + STATIC_ASSERT_SAME(Iter::pointer, const zow*); // (**) + STATIC_ASSERT_SAME(Iter::difference_type, std::ptrdiff_t); BOOST_STATIC_ASSERT((boost::is_convertible Iter; STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::reference, long&); - STATIC_ASSERT_SAME_POINTER(Iter::pointer, int*); + STATIC_ASSERT_SAME(Iter::pointer, int*); STATIC_ASSERT_SAME(Iter::difference_type, short); } return 0; diff --git a/test/pointee.cpp b/test/pointee.cpp new file mode 100755 index 0000000..b39fce1 --- /dev/null +++ b/test/pointee.cpp @@ -0,0 +1,72 @@ +// Copyright David Abrahams 2004. Use, modification and distribution is +// subject to 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 "static_assert_same.hpp" +#include +#include + +template +struct proxy_ptr +{ + typedef T element_type; + struct proxy + { + operator Ref() const; + }; + proxy operator*() const; +}; + +template +struct proxy_ref_ptr : proxy_ptr +{ +}; + +template +struct proxy_value_ptr : proxy_ptr +{ + typedef typename boost::add_const::type element_type; +}; + +struct X { + template X(T const&); + template operator T&() const; +}; + +BOOST_TT_BROKEN_COMPILER_SPEC(X) + +int main() +{ + STATIC_ASSERT_SAME(boost::pointee >::type, int); + STATIC_ASSERT_SAME(boost::pointee >::type, X); + + STATIC_ASSERT_SAME(boost::pointee >::type, int const); + STATIC_ASSERT_SAME(boost::pointee >::type, X const); + + STATIC_ASSERT_SAME(boost::pointee >::type, int const); + STATIC_ASSERT_SAME(boost::pointee >::type, X const); + + STATIC_ASSERT_SAME(boost::pointee >::type, int const); + STATIC_ASSERT_SAME(boost::pointee >::type, X const); + + STATIC_ASSERT_SAME(boost::pointee::type, int); + STATIC_ASSERT_SAME(boost::pointee::type, int const); + + STATIC_ASSERT_SAME(boost::pointee::type, X); + STATIC_ASSERT_SAME(boost::pointee::type, X const); + + STATIC_ASSERT_SAME(boost::pointee >::type, int); + STATIC_ASSERT_SAME(boost::pointee >::type, X); + + STATIC_ASSERT_SAME(boost::pointee >::type, int const); + STATIC_ASSERT_SAME(boost::pointee >::type, X const); + + STATIC_ASSERT_SAME(boost::pointee::iterator >::type, int); + STATIC_ASSERT_SAME(boost::pointee::iterator >::type, X); + + STATIC_ASSERT_SAME(boost::pointee::const_iterator >::type, int const); + STATIC_ASSERT_SAME(boost::pointee::const_iterator >::type, X const); + return 0; +}