<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 1052: reverse_iterator::operator-&gt; should also support smart pointers</title>
<meta property="og:title" content="Issue 1052: reverse_iterator::operator-&gt; should also support smart pointers">
<meta property="og:description" content="C++ library issue. Status: Resolved">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue1052.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#Resolved">Resolved</a> status.</em></p>
<h3 id="1052"><a href="lwg-defects.html#1052">1052</a>. <code>reverse_iterator::operator-&gt;</code> should also support smart pointers</h3>
<p><b>Section:</b> 24.5.1.6 <a href="https://wg21.link/reverse.iter.elem">[reverse.iter.elem]</a> <b>Status:</b> <a href="lwg-active.html#Resolved">Resolved</a>
 <b>Submitter:</b> Alisdair Meredith <b>Opened:</b> 2009-03-12 <b>Last modified:</b> 2021-06-06</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#reverse.iter.elem">issues</a> in [reverse.iter.elem].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#Resolved">Resolved</a> status.</p>
<p><b>Duplicate of:</b> <a href="lwg-closed.html#2775" title="reverse_iterator is does not compile for fancy pointers (Status: Dup)">2775</a></p>
<p><b>Discussion:</b></p>

<p><b>Addresses UK 281 [CD1]</b></p>

<p>
The current specification for return value for <code>reverse_iterator::operator-&gt;</code>
will always be a true pointer type, but <code>reverse_iterator</code> supports proxy
iterators where the pointer type may be some kind of 'smart pointer'.
</p>

<p><i>[
Summit:
]</i></p>


<blockquote>
<p>
<code>move_iterator</code> avoids this problem by returning a value of the wrapped
Iterator type.
study group formed to come up with a suggested resolution.
</p>
<p>
<code>move_iterator</code> solution shown in proposed wording.
</p>
</blockquote>

<p><i>[
2009-07 post-Frankfurt:
]</i></p>


<blockquote><p>
Howard to deconceptize. Move to Review after that happens.
</p></blockquote>

<p><i>[
2009-08-01 Howard deconceptized:
]</i></p>


<p><i>[
2009-10 Santa Cruz:
]</i></p>


<blockquote>
<p>
We can't think of any reason we can't just define reverse
iterator's pointer types to be the same as the underlying iterator's
pointer type, and get it by calling the right arrow directly.
</p>
<p>
Here is the proposed wording that was replaced:
</p>
<blockquote><pre>
template &lt;class Iterator&gt;
class reverse_iterator {
  [&hellip;]
  typedef <del>typename iterator_traits&lt;</del>Iterator<del>&gt;::pointer</del> pointer;
</pre></blockquote>

<p>
Change  [reverse.iter.opref]:
</p>

<blockquote><pre>
pointer operator-&gt;() const;
</pre>
<blockquote><p>
<i>Returns:</i>
</p><blockquote><pre>
<del>&amp;(operator*());</del>
<ins>this-&gt;tmp = current;</ins>
<ins>--this-&gt;tmp;</ins>
<ins>return this-&gt;tmp;</ins>
</pre></blockquote>
</blockquote>
</blockquote>

</blockquote>

<p><i>[
2010-03-03 Daniel opens:
]</i></p>


<blockquote>
<ol>

<li>
There is a minor problem with the exposition-only declaration of the private
member <code>deref_tmp</code> which is modified in a const member function (and the
same problem occurs in the specification of <code>operator*</code>). The fix is to
make it a mutable member.
</li>

<li>
<p>
The more severe problem is that the resolution for some reasons
does not explain in the rationale why it was decided to differ from
the suggested fix (using <code>deref_tmp</code> instead of <code>tmp</code>) in the
[ 2009-10 Santa Cruz] comment:
</p>

<blockquote><pre>
this-&gt;deref_tmp = current;
--this-&gt;deref_tmp;
return this-&gt;deref_tmp;
</pre></blockquote>

<p>
combined with the change of
</p>

<blockquote><pre>
typedef typename iterator_traits&lt;Iterator&gt;::pointer pointer;
</pre></blockquote>

<p>
to
</p>

<blockquote><pre>
typedef Iterator pointer;
</pre></blockquote>

<p>
The problem of the agreed on wording is that the following rather
typical example, that compiled with the wording before 1052 had
been applied, won't compile anymore:
</p>

<blockquote><pre>
#include &lt;iterator&gt;
#include &lt;utility&gt;

int main() {
  typedef std::pair&lt;int, double&gt; P;
  P op;
  std::reverse_iterator&lt;P*&gt; ri(&amp;op + 1);
  ri-&gt;first; // Error
}
</pre></blockquote>

<p>
Comeau online returns (if a correspondingly changed
<code>reverse_iterator</code> is used):
</p>

<blockquote><pre>
"error: expression must have class type
     return deref_tmp.operator-&gt;();
            ^
         detected during instantiation of "Iterator
                   reverse_iterator&lt;Iterator&gt;::operator-&gt;() const [with
                   Iterator=std::pair&lt;int, double&gt; *]""
</pre></blockquote>

<p>
Thus the change will break valid, existing code based
on <code>std::reverse_iterator</code>.
</p>

</li>

</ol>

<p>
IMO the suggestion proposed in the comment is a necessary fix, which harmonizes
with the similar specification of <code>std::move_iterator</code> and properly
reflects the recursive nature of the evaluation of <code>operator-&gt;</code>
overloads.
</p>

<p>
Suggested resolution:
</p>

<ol>

<li>
<p>
In the class template <code>reverse_iterator</code> synopsis of 24.5.1.2 <a href="https://wg21.link/reverse.iterator">[reverse.iterator]</a>
change as indicated:
</p>

<blockquote><pre>
namespace std {
template &lt;class Iterator&gt;
class reverse_iterator : public
             iterator&lt;typename iterator_traits&lt;Iterator&gt;::iterator_category,
             typename iterator_traits&lt;Iterator&gt;::value_type,
             typename iterator_traits&lt;Iterator&gt;::difference_type,
             <del>typename iterator_traits&lt;</del>Iterator<del>&gt;::pointer</del>,
             typename iterator_traits&lt;Iterator&gt;::reference&gt; {
public:
  [..]
  typedef <del>typename iterator_traits&lt;</del>Iterator<del>&gt;::pointer</del> pointer;
  [..]
protected:
  Iterator current;
private:
  <ins>mutable</ins> Iterator deref_tmp; // exposition only
};
</pre></blockquote>
</li>

<li>
Change  [reverse.iter.opref]/1 as indicated:

<blockquote><pre>
pointer operator-&gt;() const;
</pre>

<blockquote><p>
1 <i><del>Returns</del> <ins>Effects</ins>:</i> <del><code>&amp;(operator*())</code>.</del>
</p><blockquote><pre>
<ins>deref_tmp = current;</ins>
<ins>--deref_tmp;</ins>
<ins>return deref_tmp;</ins>
</pre></blockquote>
</blockquote>
</blockquote>

</li>

</ol>

</blockquote>

<p><i>[
2010 Pittsburgh:
]</i></p>


<blockquote>
<p>
We prefer to make to use a local variable instead of <code>deref_tmp</code> within
<code>operator-&gt;()</code>.  And although this means that the <code>mutable</code>
change is no longer needed, we prefer to keep it because it is needed for
<code>operator*()</code> anyway.
</p>

<p>
Here is the proposed wording that was replaced:
</p>

<blockquote class="note">
<p>
Change  [reverse.iter.opref]:
</p>

<blockquote><pre>
pointer operator-&gt;() const;
</pre>

<blockquote><p>
<i>Returns:</i>
</p><blockquote><pre>
<del>&amp;(operator*());</del>
<ins>deref_tmp = current;
--deref_tmp;
return deref_tmp::operator-&gt;();</ins>
</pre></blockquote>

</blockquote>
</blockquote>


</blockquote>
</blockquote>

<p><i>[
2010-03-10 Howard adds:
]</i></p>


<blockquote>
<p>
Here are three tests that the current proposed wording passes, and no
other solution I've seen passes all three:
</p>

<ol>
<li>
<p>
Proxy pointer support:
</p>
<blockquote><pre>
#include &lt;iterator&gt;
#include &lt;cassert&gt;

struct X { int m; };

X x;

struct IterX {
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef X&amp; reference;
    struct pointer
    {
        pointer(X&amp; v) : value(v) {}
        X&amp; value;
        X* operator-&gt;() const {return &amp;value;}
    };
    typedef std::ptrdiff_t difference_type;
    typedef X value_type;
    // additional iterator requirements not important for this issue

    reference operator*() const { return x; }
    pointer operator-&gt;() const { return pointer(x); }
    IterX&amp; operator--() {return *this;}

};

int main()
{
    std::reverse_iterator&lt;IterX&gt; ix;
    assert(&amp;ix-&gt;m == &amp;(*ix).m);
}
</pre></blockquote>
</li>
<li>
<p>
Raw pointer support:
</p>
<blockquote><pre>
#include &lt;iterator&gt;
#include &lt;utility&gt;

int main() {
  typedef std::pair&lt;int, double&gt; P;
  P op;
  std::reverse_iterator&lt;P*&gt; ri(&amp;op + 1);
  ri-&gt;first; // Error
}
</pre></blockquote>
</li>
<li>
<p>
Caching iterator support:
</p>
<blockquote><pre>
#include &lt;iterator&gt;
#include &lt;cassert&gt;

struct X { int m; };

struct IterX {
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef X&amp; reference;
    typedef X* pointer;
    typedef std::ptrdiff_t difference_type;
    typedef X value_type;
    // additional iterator requirements not important for this issue

    reference operator*() const { return value; }
    pointer operator-&gt;() const { return &amp;value; }
    IterX&amp; operator--() {return *this;}

private:
    mutable X value;
};

int main()
{
    std::reverse_iterator&lt;IterX&gt; ix;
    assert(&amp;ix-&gt;m == &amp;(*ix).m);
}
</pre></blockquote>
</li>
</ol>
</blockquote>

<p><i>[
2010 Pittsburgh:
]</i></p>


<blockquote><p>
Moved to NAD Future, rationale added.
</p></blockquote>

<p><i>[LEWG Kona 2017]</i></p>

<p>Recommend that we accept the "Alternate Proposed Resolution" from <a href="lwg-closed.html#2775" title="reverse_iterator is does not compile for fancy pointers (Status: Dup)">2775</a><sup><a href="https://cplusplus.github.io/LWG/issue2775" title="Latest snapshot">(i)</a></sup>.</p>

<p><i>[
Original rationale:
]</i></p>

<p>
The LWG did not reach a consensus for a change to the WP.
</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<ol>

<li>
<p>
In the class template <code>reverse_iterator</code> synopsis of 24.5.1.2 <a href="https://wg21.link/reverse.iterator">[reverse.iterator]</a> change as indicated:
</p>

<blockquote><pre>
namespace std {
template &lt;class Iterator&gt;
class reverse_iterator : public
             iterator&lt;typename iterator_traits&lt;Iterator&gt;::iterator_category,
             typename iterator_traits&lt;Iterator&gt;::value_type,
             typename iterator_traits&lt;Iterator&gt;::difference_type,
             <del>typename iterator_traits&lt;</del>Iterator<ins>&amp;</ins><del>&gt;::pointer</del>,
             typename iterator_traits&lt;Iterator&gt;::reference&gt; {
public:
  [..]
  typedef <del>typename iterator_traits&lt;</del>Iterator<ins>&amp;</ins><del>&gt;::pointer</del> pointer;
  [..]
protected:
  Iterator current;
private:
  <ins>mutable</ins> Iterator deref_tmp; // exposition only
};
</pre></blockquote>
</li>

<li>
Change  [reverse.iter.opref]/1 as indicated:

<blockquote><pre>
pointer operator-&gt;() const;
</pre>

<blockquote><p>
1 <i><del>Returns</del> <ins>Effects</ins>:</i> <del><code>&amp;(operator*())</code>.</del>
</p><blockquote><pre>
<ins>deref_tmp = current;</ins>
<ins>--deref_tmp;</ins>
<ins>return deref_tmp;</ins>
</pre></blockquote>
</blockquote>
</blockquote>

</li>

</ol>

<p><i>[Alternate Proposed Resolution from <a href="lwg-closed.html#2775" title="reverse_iterator is does not compile for fancy pointers (Status: Dup)">2775</a><sup><a href="https://cplusplus.github.io/LWG/issue2775" title="Latest snapshot">(i)</a></sup>, which was closed as a dup of this issue]</i></p>


<p>This wording is relative to N4606.</p>

<ol>
<li><p>Modify  [reverse.iter.opref] as indicated:</p>
<blockquote>
<pre>
constexpr pointer operator-&gt;() const;
</pre>
<blockquote>
<p>
-1- <del><i>Returns:</i> <code>addressof(operator*())</code>.</del><ins><i>Effects:</i> If <code>Iterator</code>
is a pointer type, as if by:</ins>
</p>
<blockquote><pre>
<ins>Iterator tmp = current;
return --tmp;</ins>
</pre></blockquote>
<p>
<ins>Otherwise, as if by:</ins>
</p>
<blockquote><pre>
<ins>Iterator tmp = current;
--tmp;
return tmp.operator-&gt;();</ins>
</pre></blockquote>
</blockquote>
</blockquote>
</li>
</ol>

</blockquote>

<p><i>[2018-08-06; Daniel rebases to current working draft and reduces the proposed wording to that preferred by LEWG]</i></p>


<p><i>[2018-11-13; Casey Carter comments]</i></p>

<p>
The acceptance of <a href="https://wg21.link/p0896r4">P0896R4</a> during the San Diego meeting resolves this
issue: The wording in [reverse.iter.elem] for <code>operator-&gt;</code> is equivalent to the PR for LWG 1052.
</p>


<p id="res-1052"><b>Proposed resolution:</b></p>

<p>
This wording is relative to <a href="https://wg21.link/n4762">N4762</a>.
</p>

<ol>
<li><p>Modify 24.5.1.6 <a href="https://wg21.link/reverse.iter.elem">[reverse.iter.elem]</a> as indicated:</p>
<blockquote>
<pre>
constexpr pointer operator-&gt;() const;
</pre>
<blockquote>
<p>
-2- <del><i>Returns:</i> <code>addressof(operator*())</code>.</del><ins><i>Effects:</i> If <code>Iterator</code>
is a pointer type, as if by:</ins>
</p>
<blockquote><pre>
<ins>Iterator tmp = current;
return --tmp;</ins>
</pre></blockquote>
<p>
<ins>Otherwise, as if by:</ins>
</p>
<blockquote><pre>
<ins>Iterator tmp = current;
--tmp;
return tmp.operator-&gt;();</ins>
</pre></blockquote>
</blockquote>
</blockquote>
</li>
</ol>






</body>
</html>
