<html>
<head><title>N4068, Toward More Expressive Iterator Tags</title></head>
<body>
<table border=0>
<tr><td><b>Doc No:</b></td><td>N4068</td></tr>
<tr><td><b>Date:</b></td><td>2014-06-28</td></tr>
<tr><td><b>Reply to:</b></td><td><tt>stdbill.h@pobox.com</tt></td></tr>
</table>
<center>
<h2>Toward More Expressive Iterator Tags</h2>
<h3>Bill Seymour<br>2014-06-28</h3>
</center>
<hr>
<h3>Introduction</h3>

During the discussion of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3976.html">N3976</a>
in Rapperswil on Tuesday, it was pointed out that certain iterators proposed in the paper claim to be
random-access iterators when, in fact, they&rsquo;re not even forward iterators.
A straw poll showed that a majority of those present were in favor of keeping
<tt>random_access_iterator_tag</tt> as the iterator category (because the more
efficient algorithms would &ldquo;probably just work&rdquo;); but there were
enough dissenting votes that calling it consensus might be a bit of a stretch.

<p>The problem is probably best solved using concepts; but we already have
iterator tags and they&rsquo;re not going away.  This short paper asks whether
there&rsquo;s interest in having more finely-grained iterator tags.
At this point, it&rsquo;s just a partly-baked idea intended to get a discussion started.

<p><hr>
<h3>Acknowledgement</h3>

Thanks to Stephan T. Lavavej for teaching me the metaprogramming trick
that I needed for writing the test code at the end of this paper.

<p><hr>
<h3>The basic idea</h3>
We&rsquo;ll start with several new iterator tags that express particular iterator requirements.
This is probably not an exhaustive list.
<ul>
<li>Whether <tt>*<i>iter</i></tt> is an actual <tt>value_type&amp;</tt> (not a proxy)
and the value is not cached in the iterator itself:
<pre>
    struct reference_tag { };
</pre>

<p><li>Whether <tt>*<i>iter</i></tt> is a modifiable lvalue or an rvalue (could be both):
<pre>
    struct lvalue_tag { };
    struct rvalue_tag { };
</pre>

<p><li>Whether <tt><i>iter1</i></tt>&nbsp;<tt>==</tt>&nbsp;<tt><i>iter2</i></tt> is well-formed:
<pre>
    struct equality_comparable_tag { };
</pre>

<p><li>Whether <tt><i>iter1</i></tt>&nbsp;<tt>==</tt>&nbsp;<tt><i>iter2</i></tt>
       implies both <tt>++<i>iter1</i></tt>&nbsp;<tt>==</tt>&nbsp;<tt><i>++iter2</i></tt>
       and <tt>&amp;*<i>iter1</i></tt>&nbsp;<tt>==</tt>&nbsp;<tt>&amp;*<i>iter2</i></tt>:
<pre>
    struct multipass_tag { };
</pre>

<p><li>Whether <tt>--<i>iter</i></tt> is well-formed:
<pre>
    struct decrementable_tag { };
</pre>

<p><li>Whether <tt><i>iter</i></tt> can be moved an arbitrary distance
and is less-than comparable:
<pre>
    struct random_move_tag { };
</pre>
</ul>
We could combine the above as:
<pre>
    template&lt;class... Tags&gt; struct basic_iterator_tag { };
</pre>

<p>And then the existing iterator tags that we all know and love could become:
<pre>
    typedef basic_iterator_tag&lt;lvalue_tag&gt; output_iterator_tag;

    typedef basic_iterator_tag&lt;rvalue_tag, equality_comparable_tag&gt;
              input_iterator_tag;

    typedef basic_iterator_tag&lt;reference_tag,
                               lvalue_tag,
                               rvalue_tag,
                               equality_comparable_tag,
                               multipass_tag&gt;
              forward_iterator_tag;

    typedef basic_iterator_tag&lt;reference_tag,
                               lvalue_tag,
                               rvalue_tag,
                               equality_comparable_tag,
                               multipass_tag,
                               decrementable_tag&gt;
              bidirectional_iterator_tag;

    typedef basic_iterator_tag&lt;reference_tag,
                               lvalue_tag,
                               rvalue_tag,
                               equality_comparable_tag,
                               multipass_tag,
                               decrementable_tag,
                               random_move_tag&gt;
              random_access_iterator_tag;
</pre>
<p><hr>
<h3>A couple of use cases</h3>
<ul>
<li>One rather obvious example would seem to be:
<pre>
    typedef basic_iterator_tag&lt;lvalue_tag,
                               rvalue_tag,
                               equality_comparable_tag,
                               multipass_tag,
                               decrementable_tag,
                               random_move_tag&gt;
              vector_bool_iterator_tag;
</pre>
Note that it lacks <tt>reference_tag</tt> in the parameter pack because <tt>*<i>iter</i></tt>
returns a proxy instead of a proper <tt>bool&amp;</tt>.

<p><li>And let's say that somebody wants to model as C++ iterators
what the database folk call &ldquo;scrolling cursors&rdquo;:
<pre>
    typedef basic_iterator_tag&lt;rvalue_tag,
                               equality_comparable_tag,
                               multipass_tag,
                               decrementable_tag,
                               random_move_tag&gt;
              scrolling_cursor_tag;
</pre>
A scrolling cursor can move back and forth by arbitrary distances;
but it lacks both <tt>reference_tag</tt> and <tt>lvalue_tag</tt>
because <tt>*<i>iter</i></tt> probably returns by <tt>const</tt> reference
a value cached in the iterator itself.

</ul>

<p><hr>
<h3>A quick test of the basic idea</h3>

<pre>
#include &lt;iostream&gt;
#include &lt;type_traits&gt;

namespace std {
namespace experimental {

//
// The proposed iterator tags:
//

struct reference_tag { };
struct lvalue_tag { };
struct rvalue_tag { };
struct equality_comparable_tag { };
struct multipass_tag { };
struct decrementable_tag { };
struct random_move_tag { };

template&lt;class... Tags&gt; struct basic_iterator_tag { };

//
// The existing iterator tags:
//

typedef basic_iterator_tag&lt;lvalue_tag&gt; output_iterator_tag;

typedef basic_iterator_tag&lt;rvalue_tag, equality_comparable_tag&gt;
          input_iterator_tag;

typedef basic_iterator_tag&lt;reference_tag,
                           lvalue_tag,
                           rvalue_tag,
                           equality_comparable_tag,
                           multipass_tag&gt;
          forward_iterator_tag;

typedef basic_iterator_tag&lt;reference_tag,
                           lvalue_tag,
                           rvalue_tag,
                           equality_comparable_tag,
                           multipass_tag,
                           decrementable_tag&gt;
          bidirectional_iterator_tag;

typedef basic_iterator_tag&lt;reference_tag,
                           lvalue_tag,
                           rvalue_tag,
                           equality_comparable_tag,
                           multipass_tag,
                           decrementable_tag,
                           random_move_tag&gt;
          random_access_iterator_tag;

//
// Whether a parameter pack contains a given type
// (probably an implementation detail in the standard library):
//

template &lt;class Required, class... Present&gt; struct _Pack_has_type;

template &lt;class Required&gt; struct _Pack_has_type&lt;Required&gt; : false_type { };

template &lt;class Required, class... Rest&gt;
  struct _Pack_has_type&lt;Required, Required, Rest...&gt; : true_type { };

template &lt;class Required, class First, class... Rest&gt;
  struct _Pack_has_type&lt;Required, First, Rest...&gt;
    : _Pack_has_type&lt;Required, Rest...&gt; { };

//
// Whether a basic_iterator_tag (Candidate) has a parameter pack that&rsquo;s
// a superset of the pack of some minimum basic_iterator_tag (Required):
//

template &lt;class Candidate, class Required&gt; struct has_iterator_tags;

template &lt;class... Candidates&gt;
  struct has_iterator_tags&lt;basic_iterator_tag&lt;Candidates...&gt;,
                           basic_iterator_tag&lt;&gt;&gt;
    : true_type { };

template &lt;class... Candidates, class Reqd1, class... ReqdRest&gt;
  struct has_iterator_tags&lt;basic_iterator_tag&lt;Candidates...&gt;,
                           basic_iterator_tag&lt;Reqd1, ReqdRest...&gt;&gt;
    : integral_constant&lt;bool,
        _Pack_has_type&lt;Reqd1, Candidates...&gt;::value &amp;&amp;
        has_iterator_tags&lt;basic_iterator_tag&lt;Candidates...&gt;,
                          basic_iterator_tag&lt;ReqdRest...&gt;&gt;::value&gt; { };

} // namespace experimental
} // namespace std

namespace {

using std::experimental::has_iterator_tags;
using std::experimental::basic_iterator_tag;
using std::experimental::random_move_tag;

namespace detail
{
    template&lt;class Iter&gt; void my_algorithm(Iter, std::false_type)
    {
        std::cout &lt;&lt; "Less efficient\n";
    }
    template&lt;class Iter&gt; void my_algorithm(Iter, std::true_type)
    {
        std::cout &lt;&lt; "More efficient\n";
    }
}

template&lt;class Iter&gt; void my_algorithm(Iter first)
{
    detail::my_algorithm(first,
      has_iterator_tags&lt;typename Iter::iterator_category,
                        basic_iterator_tag&lt;random_move_tag&gt;&gt;());
}

struct my_forward_iterator
{
    typedef std::experimental::forward_iterator_tag iterator_category;
};

struct my_random_iterator
{
    typedef std::experimental::random_access_iterator_tag iterator_category;
};

} // anonymous namespace

int main()
{
    my_algorithm(my_forward_iterator());
    my_algorithm(my_random_iterator());
}
</pre>

<p><hr>
</body>
</html>
