$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r77723 - in trunk: boost/iterator libs/iterator/test
From: jewillco_at_[hidden]
Date: 2012-04-02 14:19:45
Author: jewillco
Date: 2012-04-02 14:19:44 EDT (Mon, 02 Apr 2012)
New Revision: 77723
URL: http://svn.boost.org/trac/boost/changeset/77723
Log:
Applied patches from #5697; refs #5697
Text files modified: 
   trunk/boost/iterator/iterator_facade.hpp     |    72 ++++++++++++++++------------------      
   trunk/libs/iterator/test/iterator_facade.cpp |    82 +++++++++++++++++++++++++++++++++------ 
   2 files changed, 102 insertions(+), 52 deletions(-)
Modified: trunk/boost/iterator/iterator_facade.hpp
==============================================================================
--- trunk/boost/iterator/iterator_facade.hpp	(original)
+++ trunk/boost/iterator/iterator_facade.hpp	2012-04-02 14:19:44 EDT (Mon, 02 Apr 2012)
@@ -14,8 +14,8 @@
 #include <boost/iterator/detail/facade_iterator_category.hpp>
 #include <boost/iterator/detail/enable_if.hpp>
 
-#include <boost/implicit_cast.hpp>
 #include <boost/static_assert.hpp>
+#include <boost/utility/addressof.hpp>
 
 #include <boost/type_traits/is_same.hpp>
 #include <boost/type_traits/add_const.hpp>
@@ -294,46 +294,43 @@
 
     // operator->() needs special support for input iterators to strictly meet the
     // standard's requirements. If *i is not a reference type, we must still
-    // produce a lvalue to which a pointer can be formed. We do that by
-    // returning an instantiation of this special proxy class template.
-    template <class T>
-    struct operator_arrow_proxy
-    {
-        operator_arrow_proxy(T const* px) : m_value(*px) {}
-        T* operator->() const { return &m_value; }
-        // This function is needed for MWCW and BCC, which won't call operator->
-        // again automatically per 13.3.1.2 para 8
-        operator T*() const { return &m_value; }
-        mutable T m_value;
-    };
-
-    // A metafunction that gets the result type for operator->.  Also
-    // has a static function make() which builds the result from a
-    // Reference
-    template <class ValueType, class Reference, class Pointer>
-    struct operator_arrow_result
-    {
-        // CWPro8.3 won't accept "operator_arrow_result::type", and we
-        // need that type below, so metafunction forwarding would be a
-        // losing proposition here.
-        typedef typename mpl::if_<
-            is_reference<Reference>
-          , Pointer
-          , operator_arrow_proxy<ValueType>
-        >::type type;
+    // produce a lvalue to which a pointer can be formed.  We do that by
+    // returning a proxy object containing an instance of the reference object.
+    template <class Reference, class Pointer>
+    struct operator_arrow_dispatch // proxy references
+    {
+        struct proxy
+        {
+            explicit proxy(Reference const & x) : m_ref(x) {}
+            Reference* operator->() { return boost::addressof(m_ref); }
+            // This function is needed for MWCW and BCC, which won't call
+            // operator-> again automatically per 13.3.1.2 para 8
+            operator Reference*() { return boost::addressof(m_ref); }
+            Reference m_ref;
+        };
+        typedef proxy result_type;
+        static result_type apply(Reference const & x)
+        {
+            return result_type(x);
+        }
+    };
 
-        static type make(Reference x)
+    template <class T, class Pointer>
+    struct operator_arrow_dispatch<T&, Pointer> // "real" references
+    {
+        typedef Pointer result_type;
+        static result_type apply(T& x)
         {
-            return boost::implicit_cast<type>(&x);
+            return boost::addressof(x);
         }
     };
 
 # if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
     // Deal with ETI
     template<>
-    struct operator_arrow_result<int, int, int>
+    struct operator_arrow_dispatch<int, int>
     {
-        typedef int type;
+        typedef int result_type;
     };
 # endif
 
@@ -618,11 +615,10 @@
          Value, CategoryOrTraversal, Reference, Difference
       > associated_types;
 
-      typedef boost::detail::operator_arrow_result<
-        typename associated_types::value_type
-        , Reference
+      typedef boost::detail::operator_arrow_dispatch<
+          Reference
         , typename associated_types::pointer
-      > pointer_;
+      > operator_arrow_dispatch_;
 
    protected:
       // For use by derived classes
@@ -634,7 +630,7 @@
       typedef Reference reference;
       typedef Difference difference_type;
 
-      typedef typename pointer_::type pointer;
+      typedef typename operator_arrow_dispatch_::result_type pointer;
 
       typedef typename associated_types::iterator_category iterator_category;
 
@@ -645,7 +641,7 @@
 
       pointer operator->() const
       {
-          return pointer_::make(*this->derived());
+          return operator_arrow_dispatch_::apply(*this->derived());
       }
         
       typename boost::detail::operator_brackets_result<Derived,Value,reference>::type
Modified: trunk/libs/iterator/test/iterator_facade.cpp
==============================================================================
--- trunk/libs/iterator/test/iterator_facade.cpp	(original)
+++ trunk/libs/iterator/test/iterator_facade.cpp	2012-04-02 14:19:44 EDT (Mon, 02 Apr 2012)
@@ -7,6 +7,10 @@
 #include <boost/iterator/iterator_facade.hpp>
 #include <boost/iterator/new_iterator_tests.hpp>
 
+#include <boost/call_traits.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/utility/enable_if.hpp>
+
 // This is a really, really limited test so far.  All we're doing
 // right now is checking that the postfix++ proxy for single-pass
 // iterators works properly.
@@ -87,26 +91,76 @@
     }
 };
 
+template <class T>
+struct wrapper
+{
+    T m_x;
+    explicit wrapper(typename boost::call_traits<T>::param_type x)
+        : m_x(x)
+    { }
+    template <class U>
+    wrapper(const wrapper<U>& other,
+        typename boost::enable_if< boost::is_convertible<U,T> >::type* = 0)
+        : m_x(other.m_x)
+    { }
+};
+
+struct iterator_with_proxy_reference
+    : boost::iterator_facade<
+          iterator_with_proxy_reference
+        , wrapper<int>
+        , boost::incrementable_traversal_tag
+        , wrapper<int&>
+      >
+{
+    int& m_x;
+    explicit iterator_with_proxy_reference(int& x)
+        : m_x(x)
+    { }
+
+    void increment()
+    { }
+    wrapper<int&> dereference() const
+    { return wrapper<int&>(m_x); }
+};
+
 template <class T, class U>
 void same_type(U const&)
 { BOOST_MPL_ASSERT((boost::is_same<T,U>)); }
 
 int main()
 {
-    int state = 0;
-    boost::readable_iterator_test(counter_iterator<int const&>(&state), 0);
-    state = 3;
-    boost::readable_iterator_test(counter_iterator<proxy>(&state), 3);
-    boost::writable_iterator_test(counter_iterator<proxy>(&state), 9, 7);
-    BOOST_TEST(state == 8);
-
-    // test for a fix to http://tinyurl.com/zuohe
-    // These two lines should be equivalent (and both compile)
-    input_iter p;
-    (*p).mutator();
-    p->mutator();
+    {
+        int state = 0;
+        boost::readable_iterator_test(counter_iterator<int const&>(&state), 0);
+        state = 3;
+        boost::readable_iterator_test(counter_iterator<proxy>(&state), 3);
+        boost::writable_iterator_test(counter_iterator<proxy>(&state), 9, 7);
+        BOOST_TEST(state == 8);
+    }
+
+    {
+        // test for a fix to http://tinyurl.com/zuohe
+        // These two lines should be equivalent (and both compile)
+        input_iter p;
+        (*p).mutator();
+        p->mutator();
+
+        same_type<input_iter::pointer>(p.operator->());
+    }
+
+    {
+        int x = 0;
+        iterator_with_proxy_reference i(x);
+        BOOST_TEST(x == 0);
+        BOOST_TEST(i.m_x == 0);
+        ++(*i).m_x;
+        BOOST_TEST(x == 1);
+        BOOST_TEST(i.m_x == 1);
+        ++i->m_x;
+        BOOST_TEST(x == 2);
+        BOOST_TEST(i.m_x == 2);
+    }
 
-    same_type<input_iter::pointer>(p.operator->());
-    
     return boost::report_errors();
 }