- BREAKING CHANGE: iterator_facade::pointer now corresponds to the actual result of iterator_facade::operator-> rather than Value*. This required an adjustment to a test.

- The logic for determining the result of iterator_facade::operator[] has been factored out into a separate detail header in preparation for its potential use in iterator_range to avoid iterator_range::operator[] from returning a reference to a temporary.

[SVN r80901]
This commit is contained in:
Jeffrey Lee Hellrung, Jr 2012-10-08 02:02:09 +00:00 committed by Peter Dimov
parent 2e099caceb
commit d291c7b43e
3 changed files with 130 additions and 111 deletions

View File

@ -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 <boost/iterator/detail/facade_iterator_category.hpp>
#include <boost/type_traits/is_pod.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/mpl/if.hpp>
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 <class Value>
struct operator_brackets_value
{
typedef Value result_type;
template <class Iterator>
static result_type apply(Iterator const & i)
{ return *i; }
};
template <class Iterator, class Reference>
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 <class Iterator, class Reference>
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 <class Iterator, class ValueType, class Reference>
struct operator_brackets_dispatch
{
typedef typename mpl::if_c<
iterator_writability_disabled<ValueType,Reference>::value,
typename mpl::if_c<
boost::is_POD<ValueType>::value,
operator_brackets_value<typename boost::remove_const<ValueType>::type>,
operator_brackets_const_proxy<Iterator,Reference>
>::type,
operator_brackets_proxy<Iterator,Reference>
>::type type;
};
} } // namespace detail / namespace boost
#endif // #ifndef BOOST_OPERATOR_BRACKETS_DISPATCH_07102012JLH_HPP

View File

@ -1,6 +1,7 @@
// (C) Copyright David Abrahams 2002. // (C) Copyright David Abrahams 2002.
// (C) Copyright Jeremy Siek 2002. // (C) Copyright Jeremy Siek 2002.
// (C) Copyright Thomas Witt 2002. // (C) Copyright Thomas Witt 2002.
// (C) copyright Jeffrey Lee Hellrung, Jr. 2012.
// Distributed under the Boost Software License, Version 1.0. (See // Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at // accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
@ -13,6 +14,7 @@
#include <boost/iterator/detail/facade_iterator_category.hpp> #include <boost/iterator/detail/facade_iterator_category.hpp>
#include <boost/iterator/detail/enable_if.hpp> #include <boost/iterator/detail/enable_if.hpp>
#include <boost/iterator/detail/operator_brackets_dispatch.hpp>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#include <boost/utility/addressof.hpp> #include <boost/utility/addressof.hpp>
@ -75,7 +77,7 @@ namespace boost
, Return , Return
, int[3] , int[3]
>::type type; >::type type;
}; };
#else #else
: ::boost::iterators::enable_if< : ::boost::iterators::enable_if<
mpl::or_< mpl::or_<
@ -85,7 +87,7 @@ namespace boost
, Return , Return
> >
{}; {};
#endif #endif
// //
// Generates associated types for an iterator_facade with the // Generates associated types for an iterator_facade with the
@ -94,7 +96,7 @@ namespace boost
template < template <
class ValueParam class ValueParam
, class CategoryOrTraversal , class CategoryOrTraversal
, class Reference , class Reference
, class Difference , class Difference
> >
struct iterator_facade_types struct iterator_facade_types
@ -102,16 +104,16 @@ namespace boost
typedef typename facade_iterator_category< typedef typename facade_iterator_category<
CategoryOrTraversal, ValueParam, Reference CategoryOrTraversal, ValueParam, Reference
>::type iterator_category; >::type iterator_category;
typedef typename remove_const<ValueParam>::type value_type; typedef typename remove_const<ValueParam>::type value_type;
// Not the real associated pointer type // Not the real associated pointer type
typedef typename mpl::eval_if< typedef typename mpl::eval_if<
boost::detail::iterator_writability_disabled<ValueParam,Reference> boost::detail::iterator_writability_disabled<ValueParam,Reference>
, add_pointer<const value_type> , add_pointer<const value_type>
, add_pointer<value_type> , add_pointer<value_type>
>::type pointer; >::type pointer;
# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ # if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
&& (BOOST_WORKAROUND(_STLPORT_VERSION, BOOST_TESTED_AT(0x452)) \ && (BOOST_WORKAROUND(_STLPORT_VERSION, BOOST_TESTED_AT(0x452)) \
|| BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, BOOST_TESTED_AT(310))) \ || BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, BOOST_TESTED_AT(310))) \
@ -157,7 +159,7 @@ namespace boost
private: private:
mutable value_type stored_value; mutable value_type stored_value;
}; };
// //
// In general, we can't determine that such an iterator isn't // 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 // writable -- we also need to store a copy of the old iterator so
@ -209,7 +211,7 @@ namespace boost
{ {
return stored_iterator; return stored_iterator;
} }
private: private:
mutable value_type stored_value; mutable value_type stored_value;
Iterator stored_iterator; Iterator stored_iterator;
@ -221,7 +223,7 @@ namespace boost
struct is_non_proxy_reference_impl struct is_non_proxy_reference_impl
{ {
static Reference r; static Reference r;
template <class R> template <class R>
static typename mpl::if_< static typename mpl::if_<
is_convertible< is_convertible<
@ -231,17 +233,17 @@ namespace boost
, char[1] , char[1]
, char[2] , char[2]
>::type& helper(R const&); >::type& helper(R const&);
BOOST_STATIC_CONSTANT(bool, value = sizeof(helper(r)) == 1); BOOST_STATIC_CONSTANT(bool, value = sizeof(helper(r)) == 1);
}; };
template <class Reference, class Value> template <class Reference, class Value>
struct is_non_proxy_reference struct is_non_proxy_reference
: mpl::bool_< : mpl::bool_<
is_non_proxy_reference_impl<Reference, Value>::value is_non_proxy_reference_impl<Reference, Value>::value
> >
{}; {};
# else # else
template <class Reference, class Value> template <class Reference, class Value>
struct is_non_proxy_reference struct is_non_proxy_reference
: is_convertible< : is_convertible<
@ -250,8 +252,8 @@ namespace boost
, Value const volatile* , Value const volatile*
> >
{}; {};
# endif # endif
// A metafunction to choose the result type of postfix ++ // A metafunction to choose the result type of postfix ++
// //
// Because the C++98 input iterator requirements say that *r++ has // Because the C++98 input iterator requirements say that *r++ has
@ -273,7 +275,7 @@ namespace boost
mpl::and_< mpl::and_<
// A proxy is only needed for readable iterators // A proxy is only needed for readable iterators
is_convertible<Reference,Value const&> is_convertible<Reference,Value const&>
// No multipass iterator can have values that disappear // No multipass iterator can have values that disappear
// before positions can be re-visited // before positions can be re-visited
, mpl::not_< , mpl::not_<
@ -296,7 +298,7 @@ namespace boost
// standard's requirements. If *i is not a reference type, we must still // 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 // 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. // returning a proxy object containing an instance of the reference object.
template <class Reference, class Pointer> template <class Reference>
struct operator_arrow_dispatch // proxy references struct operator_arrow_dispatch // proxy references
{ {
struct proxy struct proxy
@ -315,10 +317,10 @@ namespace boost
} }
}; };
template <class T, class Pointer> template <class T>
struct operator_arrow_dispatch<T&, Pointer> // "real" references struct operator_arrow_dispatch<T&> // "real" references
{ {
typedef Pointer result_type; typedef T* result_type;
static result_type apply(T& x) static result_type apply(T& x)
{ {
return boost::addressof(x); return boost::addressof(x);
@ -328,79 +330,12 @@ namespace boost
# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) # if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
// Deal with ETI // Deal with ETI
template<> template<>
struct operator_arrow_dispatch<int, int> struct operator_arrow_dispatch<int>
{ {
typedef int result_type; typedef int result_type;
}; };
# endif # 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 Iterator>
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 <class ValueType, class Reference>
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<ValueType>
, iterator_writability_disabled<ValueType,Reference>
>
>
{};
template <class Iterator, class Value, class Reference>
struct operator_brackets_result
{
typedef typename mpl::if_<
use_operator_brackets_proxy<Value,Reference>
, operator_brackets_proxy<Iterator>
, Value
>::type type;
};
template <class Iterator>
operator_brackets_proxy<Iterator> make_operator_brackets_result(Iterator const& iter, mpl::true_)
{
return operator_brackets_proxy<Iterator>(iter);
}
template <class Iterator>
typename Iterator::value_type make_operator_brackets_result(Iterator const& iter, mpl::false_)
{
return *iter;
}
struct choose_difference_type struct choose_difference_type
{ {
template <class I1, class I2> template <class I1, class I2>
@ -414,13 +349,13 @@ namespace boost
, typename I1::difference_type , typename I1::difference_type
, typename I2::difference_type , typename I2::difference_type
> >
# else # else
mpl::eval_if< mpl::eval_if<
is_convertible<I2,I1> is_convertible<I2,I1>
, iterator_difference<I1> , iterator_difference<I1>
, iterator_difference<I2> , iterator_difference<I2>
> >
# endif # endif
{}; {};
}; };
@ -438,7 +373,7 @@ namespace boost
operator op( \ operator op( \
iterator_facade<Derived1, V1, TC1, Reference1, Difference1> const& lhs \ iterator_facade<Derived1, V1, TC1, Reference1, Difference1> const& lhs \
, iterator_facade<Derived2, V2, TC2, Reference2, Difference2> const& rhs) , iterator_facade<Derived2, V2, TC2, Reference2, Difference2> const& rhs)
# else # else
# define BOOST_ITERATOR_FACADE_INTEROP_HEAD(prefix, op, result_type) \ # define BOOST_ITERATOR_FACADE_INTEROP_HEAD(prefix, op, result_type) \
template < \ template < \
class Derived1, class V1, class TC1, class Reference1, class Difference1 \ class Derived1, class V1, class TC1, class Reference1, class Difference1 \
@ -451,7 +386,7 @@ namespace boost
operator op( \ operator op( \
iterator_facade<Derived1, V1, TC1, Reference1, Difference1> const& lhs \ iterator_facade<Derived1, V1, TC1, Reference1, Difference1> const& lhs \
, iterator_facade<Derived2, V2, TC2, Reference2, Difference2> const& rhs) , iterator_facade<Derived2, V2, TC2, Reference2, Difference2> const& rhs)
# endif # endif
# define BOOST_ITERATOR_FACADE_PLUS_HEAD(prefix,args) \ # define BOOST_ITERATOR_FACADE_PLUS_HEAD(prefix,args) \
template <class Derived, class V, class TC, class R, class D> \ template <class Derived, class V, class TC, class R, class D> \
@ -468,12 +403,12 @@ namespace boost
// //
class iterator_core_access 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 // Tasteless as this may seem, making all members public allows member templates
// to work in the absence of member template friends. // to work in the absence of member template friends.
public: public:
# else # else
template <class I, class V, class TC, class R, class D> friend class iterator_facade; template <class I, class V, class TC, class R, class D> friend class iterator_facade;
# define BOOST_ITERATOR_FACADE_RELATION(op) \ # define BOOST_ITERATOR_FACADE_RELATION(op) \
@ -616,14 +551,15 @@ namespace boost
> associated_types; > associated_types;
typedef boost::detail::operator_arrow_dispatch< typedef boost::detail::operator_arrow_dispatch<
Reference Reference> operator_arrow_dispatch_;
, typename associated_types::pointer
> operator_arrow_dispatch_; typedef typename boost::detail::operator_brackets_dispatch<
Derived, Value, Reference>::type operator_brackets_dispatch_;
protected: protected:
// For use by derived classes // For use by derived classes
typedef iterator_facade<Derived,Value,CategoryOrTraversal,Reference,Difference> iterator_facade_; typedef iterator_facade<Derived,Value,CategoryOrTraversal,Reference,Difference> iterator_facade_;
public: public:
typedef typename associated_types::value_type value_type; typedef typename associated_types::value_type value_type;
@ -643,16 +579,11 @@ namespace boost
{ {
return operator_arrow_dispatch_::apply(*this->derived()); return operator_arrow_dispatch_::apply(*this->derived());
} }
typename boost::detail::operator_brackets_result<Derived,Value,reference>::type typename operator_brackets_dispatch_::result_type
operator[](difference_type n) const operator[](difference_type n) const
{ {
typedef boost::detail::use_operator_brackets_proxy<Value,Reference> use_proxy; return operator_brackets_dispatch_::apply(this->derived() + n);
return boost::detail::make_operator_brackets_result<Derived>(
this->derived() + n
, use_proxy()
);
} }
Derived& operator++() Derived& operator++()
@ -671,7 +602,7 @@ namespace boost
return tmp; return tmp;
} }
# endif # endif
Derived& operator--() Derived& operator--()
{ {
iterator_core_access::decrement(this->derived()); iterator_core_access::decrement(this->derived());
@ -726,14 +657,14 @@ namespace boost
{ {
typename boost::detail::postfix_increment_result<I,V,R,TC>::type typename boost::detail::postfix_increment_result<I,V,R,TC>::type
tmp(*static_cast<I*>(&i)); tmp(*static_cast<I*>(&i));
++i; ++i;
return tmp; return tmp;
} }
# endif # endif
// //
// Comparison operator implementation. The library supplied operators // Comparison operator implementation. The library supplied operators
// enables the user to provide fully interoperable constant/mutable // enables the user to provide fully interoperable constant/mutable

View File

@ -82,7 +82,7 @@ int main()
typedef boost::indirect_iterator<char**, int, std::random_access_iterator_tag, long&, short> Iter; typedef boost::indirect_iterator<char**, int, std::random_access_iterator_tag, long&, short> Iter;
STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::value_type, int);
STATIC_ASSERT_SAME(Iter::reference, long&); 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); STATIC_ASSERT_SAME(Iter::difference_type, short);
} }
return 0; return 0;