﻿<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
    <meta charset="UTF-8"/>
    <title>string_view: a non-owning reference to a string, revision 5</title>
<style type="text/css">
body {color: #000000; background-color: #FFFFFF;}

del {text-decoration: line-through; color: #8B0040;}
ins {text-decoration: underline; color: #005100;}

pre code {display: inline-block; white-space: inherit}
code {white-space: nowrap}
code wbr {white-space: normal}

/*
.wording { max-width: 90ex; }
.wording .sectnum { margin-right: 1em; }
.wording .sectname { display: block; float: right;  }

section.numbered { counter-reset: par-num; }
.wording p:before, .wording dt:before {
    content: counter(par-num) " "; counter-increment: par-num;
    font-size: 80%; position: absolute; left: 2em}
*/
.wording td { border-top: thin solid black; border-bottom: thin solid black; }

section.function { clear: both; }
.attributes, .attribute {margin-left: 2em}

.docinfo {float: right}
.docinfo p {margin: 0; text-align:right; font-style: italic}

section {padding-left: 16px}
section h2, section h3, section h4, section h5, section h6 {margin-left: -16px}

h2, h3, h4, h5, h6 { margin-bottom: .75em }
h5, h6 { font-size: 1em; }
.wording h4 { font-size: 1.17em }
p {margin-top: .5em; margin-bottom: .5em}
p:first-child, ul, ol {margin-top: 0}
.todo dt:not(:first-child) {margin-top: .5em}
p, li, dd, table {max-width: 80ex}

table { margin: 1em; border-collapse: collapse;  border: thin solid black}
.strawpoll td {text-align: center}
.wording table { border: double; }
caption { white-space: pre; }
.wording td { text-align: left; }


.example {display: inline-block; clear: both; margin-left: 1ex;
          border: thin solid #0e0; background-color: #f8f8f8; padding: 1ex}

.ednote {display: inline-block; clear: both; margin-left: 1ex;
         border: thin solid #0e0; background-color: #f8f8f8; padding: 1ex}

div.ednote > *:first-child::before {content: "Note: "; display: inline; font-weight: bold}
div.ednote {display: inline-block; margin-left: 1ex; border: thin solid #fb6;
            padding: 1ex; background-color: #fff4dd}

:target {background-color: #fed}
</style>

</head>
<body>
  <header>
    <div class="docinfo">
      <p>ISO/IEC JTC1 SC22 WG21 N3762</p>
      <p>Date: <time pubdate="">2013-09-01</time></p>
      <address>
        <p>Jeffrey Yasskin &lt;<a href="mailto:jyasskin@google.com">jyasskin@google.com</a>&gt;</p>
      </address>
    </div>
    <h1><code>string_view</code>: a non-owning reference to a string, revision 5</h1>
  </header>
  <p><small><a href="#maincontent">Skip table of contents</a></small></p>
  <nav id="toc"></nav>
  <a id="maincontent"></a>
  <section>
    <h2 id="overview">Overview</h2>
    <p>References to strings are very common in C++ programs, but
    often the callee doesn't care about the exact type of the object
    that owns the data. 3 things generally happen in this case:</p>
    <ol>
      <li>The callee takes <code>const std::string&</code> and insists
      that callers copy the data if it was originally owned by another
      type.</li>

      <li>The callee takes two parameters&#8212;a <code>char*</code> and
      a length (or just <code>char*</code> and assumes
      0-termination)&#8212;and reduces the readability and safety of
      calls and loses any helper functions the original type
      provided.</li>

      <li>The callee is rewritten as a template and its implementation
      is moved to a header file. This can increase flexibility if the
      author takes the time to code to a weaker iterator concept, but it
      can also increase compile time and code size, and can even
      introduce bugs if the author misses an assumption that the
      argument's contents are contiguous.</li>
    </ol>

    <p>Google, LLVM, and Bloomberg have independently implemented a
    string-reference type to encapsulate this kind of argument. <a
    href="#basic.string.view"><code>string_view</code></a> is implicitly
    constructible from <code>const char*</code> and <code>std::string</code>. It
    provides the <code>const</code> member operations from
    <code>std::string</code> to ease conversion. This paper follows <a
    href="http://src.chromium.org/viewvc/chrome/trunk/src/base/strings/string_piece.h?view=markup">Chromium</a>
    and <a
    href="https://github.com/bloomberg/bsl/blob/master/groups/bsl/bslstl/bslstl_stringref.h">Bloomberg</a>
    in extending <code>string_view</code> to <code><a
    href="#basic.string.view">basic_string_view</a>&lt;charT&gt;</code>, and
    further extends it to include a <code>traits</code> parameter to match
    <code>basic_string</code>. We provide typedefs to parallel the 4
    <code>basic_string</code> typedefs.</p>

    <p>Both Google's and LLVM's <code>string_view</code> types (but not
    Bloomberg's) extend the interface from <code>std::string</code> to provide
    some helpful utility functions:</p>
    <ul>
      <li>starts_with</li>
      <li>ends_with</li>
      <li><a href="#string.view.modifiers">remove_prefix</a></li>
      <li><a href="#string.view.modifiers">remove_suffix</a></li>
      <li>split</li>
      <li>trim</li>
      <li>consume_prefix</li>
      <li>count</li>
    </ul>

    <p>Versions of <code>std::string</code> operations that take
    <code>string_view</code> instead also give the standard a way to provide
    in-place operations on non-null-terminated byte/character sequences:</p>
    <ul>
      <li><a href="#basic.string.hash">hash</a>, as requested by c++std-lib-31935</li>
      <li>In a future addition, numeric conversions</li>
    </ul>
  </section>

  <section>
    <h2 id="inventions">Inventions in this paper</h2>

    <p>Google's <code>StringPiece</code> provides <code>as_string</code> and
    <code>ToString</code> methods to convert to <code>std::string</code>. LLVM's
    <code>StringRef</code> provides both a <code>str()</code> explicit
    conversion and an implicit <code>operator std::string()</code>. Since this
    paper builds on top of C++11, we provide an <a
    href="#string.cons"><em><code>explicit</code></em> conversion
    constructor</a> as well as a less verbose <a
    href="#string.view.nonmem"><code>to_string</code> function</a>.</p>

    <p>None of the existing classes have <code>constexpr</code> methods.</p>
  </section>

  <section>
    <h2 id="bikeshed">Bikeshed!</h2>

    <p>We found rough <a
    href="https://groups.google.com/a/isocpp.org/d/topic/std-proposals/5sW8yp5i8mo/discussion">consensus
    around renaming this class to <code>string_view</code></a>. Other options
    included:</p>

    <ul>
      <li>basic_string_range (meaning a templated iterator range)</li>
      <li>char_range</li>
      <li>const_string_facade</li>
      <li>ext_string</li>
      <li>external_string</li>
      <li>str_ref</li>
      <li>string_cref (and string_ref for non-const)</li>
      <li>string_piece</li>
      <li>string_range</li>
      <li>string_ref</li>
      <li><strong>string_view</strong></li>
      <li>sub_string</li>
    </ul>
  </section>

  <section>
    <h2 id="modifications">Modifications vs std::string</h2>

    <p>The interface of <code>string_view</code> is similar to, but not exactly
    the same as the interface of <code>std::string</code>.  In general, we want
    to minimize differences between <code>std::string</code> and
    <code>string_view</code> so that users can go back and forth between the two
    often.  This section justifies the differences whose utility we think
    overcomes that general rule.</p>

    <h3 id="additions">Addition</h3>
    <ul>
      <li><code><a
      href="#string.view.modifiers">remove_prefix()</a></code> and
      <code><a
      href="#string.view.modifiers">remove_suffix()</a></code> make
      it easy to parse strings using <code>string_view</code>.  They could both
      be implemented as non-member functions (e.g. <code>str.remove_prefix(n)
      <wbr/>===<wbr/> str = str.substr(n)</code>), but it seems useful to
      provide the simplest mutators as member functions.  Note that other
      traversal primitives need to be non-members so that they're
      extensible, which may argue for pulling these out too.</li>
    </ul>
  </section>

  <section>
    <h2 id="why-not">Why not change &lt;my-pet-feature>?</h2>
    <p>I haven't taken every suggestion to change <code>string_view</code>.  This
    section explains the rationales.</p>

    <section>
      <h3 id="remove-find">Remove the find*() methods</h3>

      <p>Many people have asked why we aren't removing all of the
      <code>find<var>*</var></code> methods, since they're widely considered a
      wart on <code>std::string</code>.  First, we'd like to make it as easy as
      possible to convert code to use <code>string_view</code>, so it's useful to
      keep the interface as similar as reasonable to <code>std::string</code>.
      Second, replacing these these methods with uses of the standard algorithms
      library requires switching from indices to iterators, writing
      somewhat-complicated conversion code, and/or passing custom lambdas to
      <code>find_if</code>.  Let's look at the replacement code for each of the
      remaining methods:</p>

      <dl>
        <dt><code>haystack.find(needle)</code></dt>
        <dd>Replaced by:
        <pre class="example"><code>auto iter = std::search(haystack.begin(), haystack.end(),
                        needle.begin(), needle.end());
return iter == haystack.end() ? std::string::npos : iter - haystack.begin();</code></pre></dd>

        <dt><code>haystack.rfind(needle)</code></dt>
        <dd>Replaced by:
        <pre class="example"><code>auto iter = std::find_end(haystack.begin(), haystack.end(),
                          needle.begin(), needle.end());
return iter == haystack.end() ? std::string::npos : iter - haystack.begin();</code></pre></dd>

        <dt><code>haystack.find_first_of(needles)</code></dt>
        <dd>Replaced by:
        <pre class="example"><code>auto iter = std::find_first_of(haystack.begin(), haystack.end(),
                               needles.begin(), needles.end());
return iter == haystack.end() ? std::string::npos : iter - haystack.begin();</code></pre></dd>

        <dt><code>haystack.find_last_of(needles)</code></dt>
        <dd>Replaced by:
        <pre class="example"><code>auto iter = std::find_first_of(haystack.<strong>r</strong>begin(), haystack.<strong>r</strong>end(),
                               needles.begin(), needles.end());
return iter == haystack.<strong>r</strong>end() ? std::string::npos : iter<strong>.base() - 1</strong> - haystack.begin();</code></pre></dd>

        <dt><code>haystack.find_first_not_of(straw)</code></dt>
        <dd>Replaced by:
        <pre class="example"><code>auto iter = std::find_if(haystack.begin(), haystack.end(), [&amp;](char c) {
  return std::find(straw.begin(), straw.end(), c) == straw.end();
});
return iter == haystack.end() ? std::string::npos : iter - haystack.begin();</code></pre></dd>

        <dt><code>haystack.find_last_not_of(straw)</code></dt>
        <dd>Replaced by:
        <pre class="example"><code>auto iter = std::find_if(haystack.<strong>r</strong>begin(), haystack.<strong>r</strong>end(), [&amp;](char c) {
  return std::find(straw.begin(), straw.end(), c) == straw.end();
});
return iter == haystack.<strong>r</strong>end() ? std::string::npos : iter<strong>.base() - 1</strong> - haystack.begin();</code></pre></dd>
      </dl>

      <p><code>find</code>, <code>rfind</code>, and <code>find_first_of</code>
      are straightforward, although the conversion from indices to iterators
      would prevent many users from switching even to them.
      <code>find_last_of</code>, <code>find_first_not_of</code>, and
      <code>find_last_not_of</code> get progressively worse to handle even in an
      iterator-based function.</p>

      <p>Discussion in Bristol concluded that <code>string_view</code> should
      include all of the const signatures from <code>string</code>.</p>

      <table class="strawpoll">
        <caption>Bristol straw poll on "Should we keep the pos/n arguments to find, etc?"</caption>
        <tr><td>SF</td><td>WF</td><td>N</td><td>WA</td><td>SA</td></tr>
        <tr><td>5</td><td>4</td><td>1</td><td>2</td><td>0</td></tr>
      </table>
      <table class="strawpoll">
        <caption>Bristol straw poll on "Should we keep the copy() method?"</caption>
        <tr><td>SF</td><td>WF</td><td>N</td><td>WA</td><td>SA</td></tr>
        <tr><td>4</td><td>2</td><td>2</td><td>3</td><td>2</td></tr>
      </table>
    </section>

    <section>
      <h3 id="mutable">Make <code>basic_string_view&lt;char></code> mutable</h3>

      <p>… and use <code>basic_string_view&lt;const char></code> for the constant
      case.  The constant case is enough more common than the mutable case that
      it needs to be the default.  Making the mutable case the default would
      prevent passing string literals into <code>string_view</code> parameters,
      which would defeat a significant use case for <code>string_view</code>.  In
      a somewhat analogous sitation, LLVM defined an <a
      href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ArrayRef.h?view=log"><code>ArrayRef</code>
      class</a> in Feb 2011, and didn't find a need for the matching
      <code>MutableArrayRef</code> until Jan 2012.  They still haven't needed a
      mutable version of <a
      href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/StringRef.h?view=markup"><code>StringRef</code></a>.
      One possible reason for this is that most uses that need to modify a
      string also need to be able to change its length, and that's impossible
      through even a mutable version of <code>string_view</code>.</p>

      <p>We <em>could</em> use <code>typedef basic_string_view&lt;const char>
      string_view</code> to make the immutable case the default while still
      supporting the mutable case using the same template.  I haven't gone this
      way because it would complicate the template's definition without
      significantly helping users.</p>
    </section>

    <section>
      <h3 id="operator-bool">Add an <code>explicit operator bool</code></h3>

      <p>This would be an abbreviation for <code>!empty()</code>, usable for
      initialization in <code>if</code> statements.  <a
      href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3509.htm">N3509</a>
      came to SG9 in Bristol and was not accepted.</p>

      <table class="strawpoll">
        <caption>Bristol straw poll on "Do we want to pursue [N3509]?"</caption>
        <tr><td>SF</td><td>WF</td><td>WA</td><td>SA</td></tr>
        <tr><td>0</td><td>1</td><td>3</td><td>5</td></tr>
      </table>

    </section>

    <section>
      <h3 id="avoid-strlen">Avoid <code>strlen("string literal")</code></h3>

      <p>With a constructor of the form:</p>
      <pre class="example"><code>template&lt;size_t N>
basic_string_view(const charT (&amp;str)[N]);</code></pre>
      <p>we could avoid a <code>strlen()</code> call when a
      <code>basic_string_view</code> is constructed from a string literal.
      Unfortunately, this constructor does completely the wrong thing when
      called like:</p>
      <pre class="example"><code>char space[PATH_MAX];
snprintf(space, sizeof(space), "some string");
string_view str(space);</code></pre>
      <p>It would be possible to avoid that problem by defining a
      <code>basic_string_view(char* str)</code> that uses <code>strlen()</code>
      again, but this adds complexity.  Some people have suggested a
      <code>string_view::from_literal</code> method, but I consider that too
      verbose.</p>
      <p>Even the original worry is obsolete given modern optimizers: both gcc
      and clang optimize <code>strlen("Literal")</code> into a constant, making
      the simple, safe code as efficient as the template.  Other implementations
      should provide the same optimization as a QoI issue.</p>
    </section>

    <section>
      <h3 id="treat-as-pointer">Define comparison on <code>begin</code>/<code>end</code> instead of the elements</h3>

      <p>Operations on <code>string_view</code> apply to the characters in the
      string, and not the pointers that refer to the characters.  This
      introduces the possibility that the underlying characters might change
      while a <code>string_view</code> referring to them is in an associative
      container, which would break the container, but we believe this risk is
      worthwhile because it matches existing practice and matches user
      intentions more often.</p>
    </section>

    <section>
      <h3 id="contiguous-range">Wait for <code>contiguous_range&lt;charT></code></h3>

      <p><code>contiguous_range&lt;T></code> along with an
      <code>is_contiguous&lt;IteratorOrRange></code> trait would be useful for
      many purposes.  However, a reference class that's specifically for strings
      provides a couple extra benefits:</p>
      <ul>
        <li><code>string_view</code> can have an implicit conversion from
        <code>const char*</code>, while it would be a surprising special case to
        provide that on <code>contiguous_range&lt;const char*></code>.</li>
        <li>We can provide a subset of <code>basic_string</code>'s interface to
        ease transitions to and from ownership, while such methods would be very
        strange on <code>contiguous_range</code>.</li>
        <li><code>basic_string_view</code> takes a <code>char_traits</code>
        argument allowing customization of comparison.
        <code>contiguous_range</code> likely wouldn't.</li>
        <li>We compare and hash <code>string_view</code>s using the elements they
        refer to.  There's a stronger argument to compare a
        <code>contiguous_range</code> using the pointers inside it, meaning two
        <code>contiguous_range&lt;char></code>s of the same characters might
        compare unequal.</li>
        <li>The notion of a "string" is different from the notion of a range of
        characters, which is one reason we have <code>std::string</code> in
        addition to <code>std::vector&lt;char></code>.  Users benefit from
        saying which they mean in interfaces.</li>
      </ul>
    </section>

    <section>
      <h3 id="null-termination">Make <code>string_view</code> null-terminated</h3>

      <p>Doing this naively makes <code>substr</code> impossible to implement
      without a copy.  We could imagine inventing a more complex interface that
      records whether the input string was null-terminated, giving the user the
      option to use that string when trying to pass a <code>string_view</code> to
      a legacy or C function expecting a null-terminated <code>const
      char*</code>.  This proposal doesn't include such an interface because it
      would make <code>string_view</code> bigger or more expensive, and because
      there's no existing practice to guide us toward the right interface.</p>

      <p>Another option would be to define a separate <code>zstring_view</code>
      class to represent null-terminated strings and let it decay to
      <code>string_view</code> when necessary.  That's plausible but not part of
      this proposal.</p>
    </section>

    <section>
      <h3 id="pop-front">s/remove_prefix/pop_front/, etc.</h3>

      <p>In <a
      href="http://wiki.edg.com/twiki/bin/view/Wg21kona2012/LibraryWorkingGroup#Toward_Range_objects">Kona
      2012</a>, I proposed a <code>range&lt;></code> class with
      <code>pop_front</code>, etc. members that adjusted the bounds of the
      range.  Discussion there indicated that committee members were
      uncomfortable using the same names for lightweight range operations as
      container operations.  Existing practice doesn't agree on a name for this
      operation, so I've kept the name used by Google's
      <code>StringPiece</code>.</p>
    </section>

    <section>
      <h3 id="data-size-constructor">Allow implicit conversion from more types.</h3>

      <p><a
      href="https://groups.google.com/a/isocpp.org/d/msg/std-proposals/8t5EFJfLn0I/ms7GX_Wt4C8J">Beman
      Dawes suggested</a> defining <code>std::string_view_{begin,end}</code> and
      allowing users to add overloads within <code>std</code>.  Using ADL is a
      slight variant.  We could also allow conversion from any type with
      <code>.data()</code> and <code>.size()</code> members returning the right
      types.</p>

      <p>Ultimately, I think we want to allow this conversion based on detecting
      contiguous ranges.  Any constructor we add to work around that is going to
      look like a wart in a couple years.  I think we'll be better off making
      users explicitly convert when they can't add an appropriate conversion
      operator, and then we can add the optimal constructor when contiguous
      iterators make it into the library.</p>

      <table class="strawpoll">
        <caption>Bristol straw poll on "Should we provide this adaptation method?"</caption>
        <tr><td>SF</td><td>WF</td><td>N</td><td>WA</td><td>SA</td></tr>
        <tr><td>0</td><td>0</td><td>1</td><td>5</td><td>6</td></tr>
      </table>

    </section>
  </section>

  <section>
    <h2 id="future">Plans for future changes</h2>

    <ul>
      <li>There are many functions outside of the strings chapter that should
      incorporate <code>string_view</code>.  I'll propose those changes in a
      subsequent paper based on the <a
      href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3685.html#wording-rest">part
      of N3685</a> that isn't in this paper.</li>
      <li>We want a literal operator to produce <code>string_view</code>, maybe <code>""sv</code>.</li>
    </ul>
  </section>

  <section>
    <h2 id="revision-history">Paper revision history</h2>
    <p>This paper updates N3685 by removing other standard library updates so
    that the core <code>string_view</code> class can be accepted independently.
    I've also:</p>
    <ul>
      <li>Fixed some bugs in the <code>pos</code> and <code>n</code> parameters,</li>
      <li>Added <code>copy()</code> back,</li>
      <li>Removed the assumption that <a
      href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3687.html#2232">LWG
      issue 2232</a> will be fixed,</li>
      <li>Added a member <code>swap()</code> since it's constant time,</li>
      <li>Ensured that <code>std::swap</code> and the range access functions are
      available when <code>&lt;string_view></code> is included, and</li>
      <li>Fixed up some <code>noexcept</code>s.</li>
    </ul>

    <p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3685.html">N3685</a> updated N3609 with the results of the <a
    href="http://wiki.edg.com/twiki/bin/view/Wg21bristol/LibraryEvolutionWorkingGroup#N3609">LEWG
    discussion in Bristol</a>.  Significant changes include:</p>
    <ul>
      <li>Redirected for a TS instead of C++14</li>
      <li>Moved into a <code>&lt;string_view></code> header.</li>
      <li>Added the <code>pos</code> and <code>n</code> parameters back to <code>string_view</code> methods.</li>
      <li>Removed <code>starts_with</code> and <code>ends_with</code>.</li>
    </ul>

    <p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3609.html">N3609</a> was a minor update to N3512 that renamed the proposed class to
    <code>basic_string_view</code> and fixed some wording mistakes.</p>

    <p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3512.html">N3512</a>
    updated N3442 with wording for the <a
    href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf">draft
    C++14 standard</a>.  Note that we still aren't sure whether we're aiming for
    a TS or C++14.</p>

    <p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html">N3442</a>
    was aimed at a TS and updated
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3334.html">N3334</a>
    by removing <code>array_ref</code>.</p>

    <p>The <a
    href="https://github.com/google/cxx-std-draft/blob/string-ref-paper/string_view.html">most
    recent version of this paper</a> is maintained on GitHub.</p>
  </section>


  <hr/>

  <section class="wording">
    <h2 id="wording">Wording for TS2</h2>

    <!--<p>Wording changes are being maintained at <a
    href="https://github.com/google/cxx-std-draft/compare/string-ref">https://github.com/google/cxx-std-draft/compare/string-ref</a>
    and a snapshot of the changes is copied below.  A very early implementation
    is at <a
    href="https://github.com/google/libcxx/compare/string-ref">https://github.com/google/libcxx/compare/string-ref</a>.
    Patches and pull requests are welcome against both.</p>-->

    <h3 id="strings">Clause x, string_view</h3>

    <p>The class template <code>basic_string_view</code> describes objects that
    can refer to a constant contiguous sequence of char-like ([strings.general]) objects
    with the first element of
    the sequence at position zero. In the rest of this Clause, the type of the
    char-like objects held in a <code>basic_string_view</code>
    object is designated by <code>charT</code>.</p>

    <p>[Note: The library provides implicit conversions from <code>const
    charT*</code> and <code>std::basic_string&lt;charT, ...></code> to
    <code>std::basic_string_view&lt;charT, ...></code> so that user code can
    accept just <code>std::basic_string_view&lt;charT></code> as a non-templated
    parameter wherever a sequence of characters is expected. User-defined types
    should define their own implicit conversions to
    <code>std::basic_string_view</code> in
    order to interoperate with these functions. — end note ]</p>

    <p>The complexity of member functions is O(1) unless otherwise
    specified.</p>

    <h4>Add a "Header &lt;string_view> synopsis"</h4>

    <pre><code>namespace std {
  // [basic.string.view], basic_string_view:
  template&lt;class charT, class traits = char_traits&lt;charT>>
      class basic_string_view;

  // [string.view.comparison], non-member basic_string_view comparison functions
  template&lt;class charT, class traits>
  bool operator==(basic_string_view&lt;charT, traits> x, basic_string_view&lt;charT, traits> y) noexcept;
  template&lt;class charT, class traits>
  bool operator!=(basic_string_view&lt;charT, traits> x, basic_string_view&lt;charT, traits> y) noexcept;
  template&lt;class charT, class traits>
  bool operator&lt; (basic_string_view&lt;charT, traits> x, basic_string_view&lt;charT, traits> y) noexcept;
  template&lt;class charT, class traits>
  bool operator> (basic_string_view&lt;charT, traits> x, basic_string_view&lt;charT, traits> y) noexcept;
  template&lt;class charT, class traits>
  bool operator&lt;=(basic_string_view&lt;charT, traits> x, basic_string_view&lt;charT, traits> y) noexcept;
  template&lt;class charT, class traits>
  bool operator>=(basic_string_view&lt;charT, traits> x, basic_string_view&lt;charT, traits> y) noexcept;
  // [string.view.comparison], sufficient additional overloads of comparison functions

  // [string.view.nonmem], other non-member basic_string_view functions
  template&lt;class charT, class traits = char_traits&lt;charT>,
           class Allocator = allocator&lt;charT> >
    basic_string&lt;charT, traits, Allocator> to_string(
      basic_string_view&lt;charT, traits>,
      const Allocator& a = Allocator());

  template&lt;class charT, class traits>
    basic_ostream&lt;charT, traits>&
      operator&lt;&lt;(basic_ostream&lt;charT, traits>& os,
                 basic_string_view&lt;charT,traits> str);

  // basic_string_view typedef names
  typedef basic_string_view&lt;char> string_view;
  typedef basic_string_view&lt;char16_t> u16string_view;
  typedef basic_string_view&lt;char32_t> u32string_view;
  typedef basic_string_view&lt;wchar_t> wstring_view;

  // [string.view.hash], hash support:
  template &lt;class T> struct hash;
  template &lt;> struct hash&lt;string_view>;
  template &lt;> struct hash&lt;u16string_view>;
  template &lt;> struct hash&lt;u32string_view>;
  template &lt;> struct hash&lt;wstring_view>;
}</code></pre>

    <p>The function templates defined in [utility.swap] and [iterator.range] are
    available when <code>&lt;string_view></code> is included.</p>

    <div class="ednote"><p>Normally I would update the list in [iterator.range], but we're not yet sure how to do that in a TS, so I picked the more self-contained option.</p></div>

     <pre><code>namespace std {
  template&lt;class charT, class traits = char_traits&lt;charT>>
  class basic_string_view {
    public:
    // types
    typedef traits traits_type;
    typedef charT value_type;
    typedef const charT* pointer;
    typedef const charT* const_pointer;
    typedef const charT& reference;
    typedef const charT& const_reference;
    typedef <var>implementation-defined</var> const_iterator; // See [string.view.iterators]
    typedef const_iterator iterator;  // [Footnote: Because basic_string_view refers to a constant sequence, iterator and const_iterator are the same type. --end footnote]
    typedef reverse_iterator&lt;const_iterator> const_reverse_iterator;
    typedef const_reverse_iterator reverse_iterator;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    static constexpr size_type npos = size_type(-1);

    // [string.view.cons], construct/copy
    constexpr basic_string_view() noexcept;
    constexpr basic_string_view(const basic_string_view&) noexcept = default;
    basic_string_view& operator=(const basic_string_view&) noexcept = default;
    template&lt;class Allocator>
    basic_string_view(const basic_string&lt;charT, traits, Allocator>& str) noexcept;
    basic_string_view(const charT* str);</code></pre>
    <div class="ednote"><p>Not constexpr because that would rely on potentially-controversial changes to char_traits::length().</p></div>
<pre><code>    constexpr basic_string_view(const charT* str, size_type len);</code></pre>
    <div class="ednote"><p>No initializer_list constructor because [dcl.init.list]p6 says it would likely store a dangling reference into the <code>basic_string_view</code>.</p></div>

<pre><code>    // [string.view.iterators], iterators
    constexpr const_iterator begin() const noexcept;
    constexpr const_iterator end() const noexcept;
    constexpr const_iterator cbegin() const noexcept;
    constexpr const_iterator cend() const noexcept;</code></pre>
    <div class="ednote"><p>reverse_iterator methods aren’t constexpr because reverse_iterator isn’t a literal type. See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3473.html#2208">LWG Issue 2208</a>.</p></div>
<pre><code>    const_reverse_iterator rbegin() const noexcept;
    const_reverse_iterator rend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // [string.view.capacity], capacity
    constexpr size_type size() const noexcept;
    constexpr size_type length() const noexcept;
    constexpr size_type max_size() const noexcept;
    constexpr bool empty() const noexcept;

    // [string.view.access], element access
    constexpr const charT& operator[](size_type pos) const;
    constexpr const charT& at(size_type pos) const;
    constexpr const charT& front() const;
    constexpr const charT& back() const;
    constexpr const charT* data() const noexcept;

    // [string.view.modifiers], modifiers:
    void clear() noexcept;
    void remove_prefix(size_type n);
    void remove_suffix(size_type n);
    void swap(basic_string_view& s) noexcept;

    // [string.view.ops], string operations:
    template&lt;class Allocator>
    explicit operator basic_string&lt;charT, traits, Allocator>() const;

    size_type copy(charT* s, size_type n, size_type pos = 0) const;

    constexpr basic_string_view substr(size_type pos=0, size_type n=npos) const;
    int compare(basic_string_view s) const noexcept;
    int compare(size_type pos1, size_type n1, basic_string_view s) const;
    int compare(size_type pos1, size_type n1,
                basic_string_view s, size_type pos2, size_type n2) const;
    int compare(const charT* s) const;
    int compare(size_type pos1, size_type n1, const charT* s) const;
    int compare(size_type pos1, size_type n1,
                const charT* s, size_type n2) const;
    size_type find(basic_string_view s, size_type pos=0) const noexcept;
    size_type find(charT c, size_type pos=0) const noexcept;
    size_type find(const charT* s, size_type pos, size_type n) const;
    size_type find(const charT* s, size_type pos=0) const;
    size_type rfind(basic_string_view s, size_type pos=npos) const noexcept;
    size_type rfind(charT c, size_type pos=npos) const noexcept;
    size_type rfind(const charT* s, size_type pos, size_type n) const;
    size_type rfind(const charT* s, size_type pos=npos) const;
    size_type find_first_of(basic_string_view s, size_type pos=0) const noexcept;
    size_type find_first_of(charT c, size_type pos=0) const noexcept;
    size_type find_first_of(const charT* s, size_type pos, size_type n) const;
    size_type find_first_of(const charT* s, size_type pos=0) const;
    size_type find_last_of(basic_string_view s, size_type pos=npos) const noexcept;
    size_type find_last_of(charT c, size_type pos=npos) const noexcept;
    size_type find_last_of(const charT* s, size_type pos, size_type n) const;
    size_type find_last_of(const charT* s, size_type pos=npos) const;
    size_type find_first_not_of(basic_string_view s, size_type pos=0) const noexcept;
    size_type find_first_not_of(charT c, size_type pos=0) const noexcept;
    size_type find_first_not_of(const charT* s, size_type pos, size_type n) const;
    size_type find_first_not_of(const charT* s, size_type pos=0) const;
    size_type find_last_not_of(basic_string_view s, size_type pos=npos) const noexcept;
    size_type find_last_not_of(charT c, size_type pos=npos) const noexcept;
    size_type find_last_not_of(const charT* s, size_type pos, size_type n) const;
    size_type find_last_not_of(const charT* s, size_type pos=npos) const;
  };
}</code></pre>

    <p>In every specialization <code>basic_string_view&lt;charT, traits></code>,
    the type <code>traits</code> shall satisfy the character traits
    requirements ([char.traits]), and the type <code>traits::char_type</code>
    shall name the same type as <code>charT</code>.</p>

    <p>Each member function of the form</p>
    <pre><code>rt fx1(const charT* s[, size_type pos[, size_type n]]); // find() variants</code></pre>
    <p>is equivalent to <code>return fx1(basic_string_view(s[, n])[, pos])</code>.</p>

    <p>Each member function of the form</p>
    <pre><code>rt fx2(charT c, size_type pos); // find() variants</code></pre>
    <p>is equivalent to <code>return fx2(basic_string_view(&c, 1), pos)</code>.</p>

    <h4>Add a subclause "x.1 basic_string_view constructors and assignment operators  [string.view.cons]"</h4>

    <pre><code>constexpr basic_string_view() noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Constructs an empty basic_string_view.</p>
      <p><i>Postcondition</i>: empty() == true and [data(),data()) is a valid range.</p>
    </div>

    <pre><code>template&lt;class Allocator>
basic_string_view(const basic_string&lt;charT, traits, Allocator>& str) noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Constructs a basic_string_view, with the postconditions in Table [tab:string.view.ctr.1]</p>
      <p><i>Remarks</i>: The program shall not alter any of the values stored in the character array. [Footnote: This is the same requirement as on <code>str.data()</code> -- end footnote]</p>
      <table><caption>Table [tab:string.view.ctr.1] — basic_string_view(const basic_string&) effects</caption>
      <tr><th>Element</th><th>Value</th></tr>
      <tr><td>data()</td><td>str.data()</td></tr>
      <tr><td>size()</td><td>str.size()</td></tr>
      </table>
    </div>

    <pre><code>basic_string_view(const charT* str);</code></pre>
    <div class="attributes">
      <p><i>Requires</i>: [str,str + traits::length(str)) is a valid range.</p>
      <p><i>Effects</i>: Constructs a basic_string_view referring to the same string as str, with the postconditions
      in Table [tab:string.view.ctr.2]</p>

      <table><caption>Table [tab:string.view.ctr.2] — basic_string_view(const charT*) effects</caption>
      <tr><th>Element</th><th>Value</th></tr>
      <tr><td>data()</td><td>str</td></tr>
      <tr><td>size()</td><td>traits::length(str)</td></tr>
      </table>

      <p><i>Complexity</i>: O(size())</p>
    </div>

    <pre><code>constexpr basic_string_view(const charT* str, size_type len);</code></pre>
    <div class="attributes">
      <p><i>Requires</i>: str is not a null pointer and [str,str + len) is a valid range.</p>
      <p><i>Effects</i>: Constructs a basic_string_view, with the postconditions in Table [tab:string.view.ctr.3]</p>
      <table><caption>Table [tab:string.view.ctr.3] — basic_string_view(const charT*, size_type) effects</caption>
      <tr><th>Element</th><th>Value</th></tr>
      <tr><td>data()</td><td>str</td></tr>
      <tr><td>size()</td><td>len</td></tr>
      </table>
    </div>


    <h4>Add a subclause "x.2 basic_string_view iterator support [string.view.iterators]"</h4>

    <pre><code>typedef implementation-defined const_iterator;</code></pre>
    <div class="attributes">
      <p>A constant random-access iterator type such that, for a <code>const_iterator it</code>,
      if <code>&amp;*(it+N)</code> is valid, then it is equal to <code>(&amp;*it)+N</code>.</p>
      <p>For a basic_string_view str, any operation that invalidates a pointer in
      the range [str.data(), str.data()+str.size()) invalidates pointers and
      iterators returned from str’s methods.</p>
      <p>All requirements on container iterators ([container.requirements])
      apply to <code>basic_string_view::const_iterator</code> as well.</p>
    </div>


    <pre><code>constexpr const_iterator begin() const noexcept;
constexpr const_iterator cbegin() const noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: An iterator referring to the first character in the string.</p>

    <pre><code>constexpr const_iterator end() const noexcept;
constexpr const_iterator cend() const noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: An iterator which is the past-the-end value.</p>

    <pre><code>const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator crbegin() const noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: An iterator which is semantically equivalent to reverse_iterator(end()).</p>

    <pre><code>const_reverse_iterator rend() const noexcept;
const_reverse_iterator crend() const noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: An iterator which is semantically equivalent to reverse_iterator(begin()).</p>

    <h4>Add a subclause "x.3 basic_string_view capacity [string.view.capacity]"</h4>

    <pre><code>constexpr size_type size() const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Returns</i>: A count of the number of char-like objects referred to by the <code>basic_string_view</code>.</p>
    </div>

    <pre><code>constexpr size_type length() const noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: size().</p>

    <pre><code>constexpr size_type max_size() const noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: The size of the largest possible <code>basic_string_view</code>.</p>

    <pre><code>constexpr bool empty() const noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: size() == 0.</p>


    <h4>Add a subclause "x.4 basic_string_view element access [string.view.access]"</h4>

    <pre><code>constexpr const_reference operator[](size_type pos) const;</code></pre>
    <div class="attributes">
      <p><i>Requires</i>: pos &lt; size().</p>
      <p><i>Returns</i>: *(begin() + pos)</p>
      <p><i>Throws</i>: Nothing.</p>
      <p>[ Note: Unlike basic_string::operator[],
      basic_string_view::operator[](size()) has undefined behavior instead of
      returning charT(). — end note ]</p>
    </div>

    <pre><code>constexpr const_reference at(size_type pos) const;</code></pre>
    <div class="attributes">
      <p><i>Throws</i>: out_of_range if pos >= size().</p>
      <p><i>Returns</i>: operator[](pos).</p>
    </div>

    <pre><code>constexpr const charT& front() const;</code></pre>
    <div class="attributes">
      <p><i>Requires</i>: !empty()</p>
      <p><i>Effects</i>: Equivalent to <code>return operator[](0)</code>.</p>
    </div>

    <pre><code>constexpr const charT& back() const;</code></pre>
    <div class="attributes">
      <p><i>Requires</i>: !empty()</p>
      <p><i>Effects</i>: Equivalent to <code>return operator[](size() - 1)</code>.</p>
    </div>

    <pre><code>constexpr const charT* data() const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Returns</i>: A non-null pointer p such that p + i == &operator[](i) for each i in [0,size()).</p>
      <p>[ Note: Unlike std::string::data() and string literals, data() may
      return a pointer to a buffer that is not null-terminated. Therefore it is
      typically a mistake to pass data() to a routine that takes just a const
      charT* and expects a null-terminated string. — end note ]</p>
    </div>

    <h4 id="string.view.modifiers">Add a subclause "x.5 basic_string_view modifiers [string.view.modifiers]"</h4>

    <pre><code>void clear() noexcept;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>*this = basic_string_view()</code></p>

    <pre><code>void remove_prefix(size_type n);</code></pre>
    <div class="attributes">
      <p><i>Requires</i>: <code>n &lt;= size()</code></p>
      <p><i>Effects</i>: Equivalent to <code>*this = substr(n, npos)</code></p>
    </div>

    <pre><code>void remove_suffix(size_type n);</code></pre>
    <div class="attributes">
      <p><i>Requires</i>: <code>n &lt;= size()</code></p>
      <p><i>Effects</i>: Equivalent to <code>*this = substr(0, size() - n)</code></p>
    </div>

    <pre><code>void swap(basic_string_view& s) noexcept</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Exchanges the values of <code>*this</code> and <code>s</code>.</p>
    </div>


    <h4 id="string.view.ops">Add a subclause "x.6 basic_string_view string operations [string.view.ops]"</h4>

    <pre><code>template&lt;class Allocator>
explicit  // Footnote: This conversion is explicit to avoid accidental O(N) operations on type mismatches. --end footnote
operator basic_string&lt;charT, traits, Allocator>() const;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Equivalent to <code>return basic_string&lt;charT, traits, Allocator>(str.begin(), str.end()).</code></p>
      <p>[ Note: Users who want to control the allocator instance should call <code>basic_string(str.begin(), str.end(), allocator)</code> directly. -- end note ]</p>
    </div>

    <pre><code>size_type copy(charT* s, size_type n, size_type pos = 0) const;</code></pre>
    <div class="attributes">
      <p><i>Throws</i>: <code>out_of_range</code> if <code>pos > size()</code>.</p>
      <p><i>Remarks</i>: Let <code><var>rlen</var></code> be the smaller of <code>n</code> and <code>size() - pos</code>.</p>
      <p><i>Requires</i>: [<code>s</code>, <code>s+<var>rlen</var></code>) is a valid range.</p>
      <p><i>Effects</i>: Equivalent to <code>std::copy_n(begin() + pos, <var>rlen</var>, s).</code></p>
      <p><i>Returns</i>: <code><var>rlen</var></code>.</p>
    </div>

    <pre><code>constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const;</code></pre>
    <div class="attributes">
      <p><i>Throws</i>: out_of_range if pos > size().</p>
      <p><i>Effects</i>: Determines the effective length rlen of the string to reference as the smaller of n and size() - pos.</p>
      <p><i>Returns</i>: basic_string_view(data()+pos, rlen).</p>
    </div>

    <pre><code>int compare(basic_string_view str) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the effective length rlen of the strings to compare as the smallest of size() and str.size(). The function then compares the two strings by calling traits::compare(data(), str.data(), rlen).</p>
      <p><i>Complexity</i>: O(rlen)</p>
      <p><i>Returns</i>: The nonzero result if the result of the comparison is nonzero. Otherwise, returns a value as
      indicated in Table [tab:string.view.compare].</p>
      <table><caption>Table [tab:string.view.compare] — compare() results</caption>
      <tr><th>Condition</th><th>Return Value</th></tr>
      <tr><td>size() &lt; str.size()</td><td>&lt; 0</td></tr>
      <tr><td>size() == str.size()</td><td>0</td></tr>
      <tr><td>size() >  str.size()</td><td>> 0</td></tr>
      </table>
    </div>

    <pre><code>int compare(size_type pos1, size_type n1, basic_string_view str) const;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>return substr(pos1, n1).compare(str)</code>.</p>

    <pre><code>int compare(size_type pos1, size_type n1, basic_string_view str,
            size_type pos2, size_type n2) const;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>return substr(pos1, n1).compare(str.substr(pos2, n2))</code>.</p>
    <pre><code>int compare(const charT* s) const;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>return compare(basic_string_view(s))</code>.</p>
    <pre><code>int compare(size_type pos1, size_type n1, const charT* s) const;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>return substr(pos1, n1).compare(basic_string_view(s))</code>.</p>
    <pre><code>int compare(size_type pos1, size_type n1,
            const charT* s, size_type n2) const;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>return substr(pos1, n1).compare(basic_string_view(s, n2))</code>.</p>

    <h5>Add a sub-subclause "x.6.1 Searching basic_string_view [string.view.find]"</h5>

    <p>Member functions in this section have complexity O(size() *
    argument.size()) at worst, although implementations are encouraged to do
    better.</p>

    <pre><code>size_type find(basic_string_view str, size_type pos=0) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the lowest position xpos, if possible, such that the following conditions obtain:</p>
      <ul><li>pos &lt;= xpos</li>
      <li>xpos + str.size() &lt;= size();</li>
      <li>traits::eq(at(xpos+I), str.at(I)) for all elements I of the string referenced by str.</li>
      </ul>
      <p><i>Returns</i>: xpos if the function can determine such a value for xpos. Otherwise, returns npos.</p>
      <p><i>Remarks</i>: Uses traits::eq().</p>
    </div>

    <pre><code>size_type rfind(basic_string_view str, size_type pos=npos) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the highest position xpos, if possible, such that the following conditions obtain:</p>
      <ul><li>xpos &lt;= pos</li>
      <li>xpos + str.size() &lt;= size();</li>
      <li>traits::eq(at(xpos+I), str.at(I)) for all elements I of the string referenced by str.</li></ul>
      <p><i>Returns</i>: xpos if the function can determine such a value for xpos. Otherwise, returns npos.</p>
      <p><i>Remarks</i>: Uses traits::eq().</p>
    </div>

    <pre><code>size_type find_first_of(basic_string_view str, size_type pos=0) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the lowest position xpos, if possible, such that the following conditions obtain:</p>
      <ul><li>pos &lt;= xpos</li>
      <li>xpos &lt; size();</li>
      <li>traits::eq(at(xpos), str.at(I)) for some element I of the string referenced by str.</li></ul>
      <p><i>Returns</i>: xpos if the function can determine such a value for xpos. Otherwise, returns npos.</p>
      <p><i>Remarks</i>: Uses traits::eq().</p>
    </div>

    <pre><code>size_type find_last_of(basic_string_view str, size_type pos=npos) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the highest position xpos, if possible, such that the following conditions obtain:</p>
      <ul><li>xpos &lt;= pos</li>
      <li>xpos &lt; size();</li>
      <li>traits::eq(at(xpos), str.at(I)) for some element I of the string referenced by str.</li></ul>
      <p><i>Returns</i>: xpos if the function can determine such a value for xpos. Otherwise, returns npos.</p>
      <p><i>Remarks</i>: Uses traits::eq().</p>
    </div>

    <pre><code>size_type find_first_not_of(basic_string_view str, size_type pos=0) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the lowest position xpos, if possible, such that the following conditions obtain:</p>
      <ul><li>pos &lt;= xpos</li>
      <li>xpos &lt; size();</li>
      <li>traits::eq(at(xpos), str.at(I)) for no element I of the string referenced by str.</li></ul>
      <p><i>Returns</i>: xpos if the function can determine such a value for xpos. Otherwise, returns npos.</p>
      <p><i>Remarks</i>: Uses traits::eq().</p>
    </div>

    <pre><code>size_type find_last_not_of(basic_string_view str, size_type pos=npos) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the highest position xpos, if possible, such that the following conditions obtain:</p>
      <ul><li>xpos &lt;= pos</li>
      <li>xpos &lt; size();</li>
      <li>traits::eq(at(xpos), str.at(I)) for no element I of the string referenced by str.</li></ul>
      <p><i>Returns</i>: xpos if the function can determine such a value for xpos. Otherwise, returns npos.</p>
      <p><i>Remarks</i>: Uses traits::eq().</p>
    </div>


    <h4>Add a subclause "x.7 basic_string_view non-member comparison functions [string.view.comparison]"</h4>

    <p>Implementations shall provide sufficient additional overloads so that an
    object <code><var>t</var></code> with an implicit conversion to
    <code>basic_string_view&lt;charT, traits></code> can be compared according to
    Table [tab:string.view.comparison.overloads], where
    <code><var>sp</var></code> is an instance of
    <code>basic_string_view&lt;charT, traits></code>.</p>

    <table><caption>Table [tab:string.view.comparison.overloads] —<wbr/> Additional basic_string_view comparison overloads</caption>
    <tr><th>Expression</th><th>Equivalent to</th></tr>
    <tr><td>t == sp</td><td>basic_string_view&lt;charT, traits>(t) == sp</td></tr>
    <tr><td>sp == t</td><td>sp == basic_string_view&lt;charT, traits>(t)</td></tr>
    <tr><td>t != sp</td><td>basic_string_view&lt;charT, traits>(t) != sp</td></tr>
    <tr><td>sp != t</td><td>sp != basic_string_view&lt;charT, traits>(t)</td></tr>
    <tr><td>t &lt; sp</td><td>basic_string_view&lt;charT, traits>(t) &lt; sp</td></tr>
    <tr><td>sp &lt; t</td><td>sp &lt; basic_string_view&lt;charT, traits>(t)</td></tr>
    <tr><td>t > sp</td><td>basic_string_view&lt;charT, traits>(t) > sp</td></tr>
    <tr><td>sp > t</td><td>sp > basic_string_view&lt;charT, traits>(t)</td></tr>
    <tr><td>t &lt;= sp</td><td>basic_string_view&lt;charT, traits>(t) &lt;= sp</td></tr>
    <tr><td>sp &lt;= t</td><td>sp &lt;= basic_string_view&lt;charT, traits>(t)</td></tr>
    <tr><td>t >= sp</td><td>basic_string_view&lt;charT, traits>(t) >= sp</td></tr>
    <tr><td>sp >= t</td><td>sp >= basic_string_view&lt;charT, traits>(t)</td></tr>
    </table>

    <p>[ Example: A sample conforming implementation for operator== would be:</p>
<pre><code>  template&lt;class T> struct __identity { typedef T type; };
  template&lt;class charT, class traits>
  bool operator==(basic_string_view&lt;charT, traits> lhs,
                  basic_string_view&lt;charT, traits> rhs) noexcept {
    return lhs.compare(rhs) == 0;
  }
  template&lt;class charT, class traits>
  bool operator==(basic_string_view&lt;charT, traits> lhs,
                  typename __identity&lt;basic_string_view&lt;charT, traits>>::type rhs) noexcept {
    return lhs.compare(rhs) == 0;
  }
  template&lt;class charT, class traits>
  bool operator==(typename __identity&lt;basic_string_view&lt;charT, traits>>::type lhs,
                  basic_string_view&lt;charT, traits> rhs) noexcept {
    return lhs.compare(rhs) == 0;
}</code></pre>
    <p>— end example ]</p>

<pre><code>template&lt;class charT, class traits>
  bool operator==(basic_string_view&lt;charT,traits> lhs,
                  basic_string_view&lt;charT,traits> rhs) noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: lhs.compare(rhs) == 0.</p>

<pre><code>template&lt;class charT, class traits>
  bool operator!=(basic_string_view&lt;charT,traits> lhs,
                  basic_string_view&lt;charT,traits> rhs) noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: !(lhs == rhs).</p>

<pre><code>template&lt;class charT, class traits>
  bool operator&lt; (basic_string_view&lt;charT,traits> lhs,
                  basic_string_view&lt;charT,traits> rhs) noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: lhs.compare(rhs) &lt; 0.</p>

<pre><code>template&lt;class charT, class traits>
  bool operator> (basic_string_view&lt;charT,traits> lhs,
                  basic_string_view&lt;charT,traits> rhs) noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: lhs.compare(rhs) > 0.</p>

<pre><code>template&lt;class charT, class traits>
  bool operator&lt;=(basic_string_view&lt;charT,traits> lhs,
                  basic_string_view&lt;charT,traits> rhs) noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: lhs.compare(rhs) &lt;= 0.</p>

<pre><code>template&lt;class charT, class traits>
  bool operator>=(basic_string_view&lt;charT,traits> lhs,
                  basic_string_view&lt;charT,traits> rhs) noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: lhs.compare(rhs) >= 0.</p>

    <h4 id="string.view.nonmem">Add a subclause "x.8 Other basic_string_view non-member functions [string.view.nonmem]"</h4>

    <pre><code>template&lt;class charT, class traits = char_traits&lt;charT>,
         class Allocator = allocator&lt;charT> >
  basic_string&lt;charT, traits, Allocator> to_string(
    basic_string_view&lt;charT, traits> str,
    const Allocator& a = Allocator());</code></pre>
    <div class="attributes">
      <p><i>Complexity</i>: O(str.size())</p>
      <p><i>Returns</i>: basic_string&lt;charT, traits, Allocator>(str.begin(), str.end(), a).</p>
    </div>

    <h4>Add a subclause "x.9 Inserters and extractors [string.view.io]</h4>

    <pre><code>template&lt;class charT, class traits>
  basic_ostream&lt;charT, traits>&
    operator&lt;&lt;(basic_ostream&lt;charT, traits>& os,
               basic_string_view&lt;charT,traits> str);</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Behaves as a formatted output function
      ([ostream.formatted.reqmts]) of <code>os</code>. Forms a character
      sequence <code>seq</code>, initially consisting of the elements defined by
      the range <code>[str.begin(), str.end())</code>. Determines padding for
      <code>seq</code> as described in [ostream.formatted.reqmts]. Then inserts
      <code>seq</code> as if by calling <code>os.rdbuf()->sputn(seq, n)</code>,
      where <code>n</code> is the larger of <code>os.width()</code> and
      <code>str.size()</code>; then calls <code>os.width(0)</code>.</p>
      <p><i>Returns</i>: os</p>
    </div>


    <h4 id="basic.string.hash">Add a subclause "x.10 Hash support [string.view.hash]"</h4>

    <pre><code>template &lt;> struct hash&lt;string_view>;
template &lt;> struct hash&lt;u16string_view>;
template &lt;> struct hash&lt;u32string_view>;
template &lt;> struct hash&lt;wstring_view>;</code></pre>
    <p class="attribute"><i>Requires</i>: the template specializations shall
    meet the requirements of class template hash ([unord.hash]).</p>

  </section>

  <section>
    <h2 id="acknowledgements">Acknowledgements</h2>

    <p>I'd like to thank Marshall Clow, Olaf van der Spek, the Boost and
    std-proposals mailing lists, Chandler Carruth, Beman Dawes, Alisdair
    Meredith, and especially Daniel Krügler for help, advice, and wording in
    this paper.</p>
  </section>

  <script type="text/javascript"><!--
/**
 * This code is compiled from h5o, with the patches in issues 18, 19, and 2
 * (https://code.google.com/p/h5o/issues/list).
 *
 * This code contains an implementation of HTML5 outlining algorithm, as described by WHATWG at [1]
 *
 * The copyright notice at [2] says:
 *              (c) Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera Software ASA.
 *              You are granted a license to use, reproduce and create derivative works of this document.
 *
 * [1] http://www.whatwg.org/specs/web-apps/current-work/multipage/sections.html#outlines
 * [2] http://www.whatwg.org/specs/web-apps/current-work/multipage/index.html
 */
(function(){var j=function(b){this.sections=[];this.startingNode=b};j.prototype={heading:!1,append:function(b){b.container=this;this.sections.push(b)},asHTML:function(b){"object"!=typeof b&&(b={createLinks:b});var a;a=this.heading;g(a)?("HGROUP"==a.tagName.toUpperCase()&&(a=a.getElementsByTagName("h"+-k(a))[0]),a=a.textContent||a.innerText||"<i>No text content inside "+a.nodeName+"</i>"):a=""+a;if(b.createLinks){var e;a:{e=this.startingNode;for(var d,c=e;;){if(d=c.getAttribute("id")){e=d;break a}for(c=
c.firstChild;c&&3==c.nodeType&&!/\S/.test(c.data);)c=c.nextSibling;if(!g(c))break}do d="h5o-"+ ++q;while(r.getElementById(d));e.setAttribute("id",d);e=d}a='<a href="#'+e+'">'+a+"</a>"}return a+n(this.sections,b)}};var n=function(b,a){if(a.skipTopHeader)return a.skipTopHeader=!1,n(b[0].sections,a);for(var c="",d=0;d<b.length;d++){var f=b[d];a.skipUntitled&&"string"==typeof f.heading||(c+="<li>"+f.asHTML(a)+"</li>")}return""==c?c:"<ol>"+c+"</ol>"},s=function(b){b=b.heading;return g(b)?k(b):1},c,d,f,
q,r,t=function(b){if(!g(f[f.length-1]))if(l(b)||m(b))null!=c&&f.push(c),c=b,d=new j(b),c.outline={sections:[d],startingNode:b,asHTML:function(a){return n(this.sections,a)}};else if(null!=c&&g(b)){if(d.heading)if(k(b)>=s(c.outline.sections[c.outline.sections.length-1])){var a=new j(b);c.outline.sections.push(a);d=a;d.heading=b}else{var a=!1,e=d;do k(b)<s(e)&&(a=new j(b),e.append(a),d=a,d.heading=b,a=!0),e=e.container;while(!a)}else d.heading=b;f.push(b)}},p=function(b){return function(a){return a&&
a.tagName&&RegExp(b,"i").test(a.tagName.toUpperCase())}},m=p("^BLOCKQUOTE|BODY|DETAILS|FIELDSET|FIGURE|TD$"),l=p("^ARTICLE|ASIDE|NAV|SECTION$"),g=p("^H[1-6]|HGROUP$"),k=function(b){var a=b.tagName.toUpperCase();if("HGROUP"==a)for(a=1;6>=a;a++){if(0<b.getElementsByTagName("H"+a).length)return-a}else return-parseInt(a.substr(1))};HTML5Outline=function(b){q=0;r=b.ownerDocument||window.document;d=c=null;f=[];var a=b;a:for(;a;){t(a);if(a.firstChild){a=a.firstChild;continue a}for(;a;){var e=a,h=f[f.length-
1];if(g(h))h==e&&f.pop();else{if((l(e)||m(e))&&!d.heading)d.heading="<i>Untitled "+e.tagName.toUpperCase()+"</i>";if(l(e)&&0<f.length){c=f.pop();d=c.outline.sections[c.outline.sections.length-1];for(h=0;h<e.outline.sections.length;h++)d.append(e.outline.sections[h])}else if(m(e)&&0<f.length){c=f.pop();for(d=c.outline.sections[c.outline.sections.length-1];0<d.sections.length;)d=d.sections[d.sections.length-1]}else if(l(e)||m(e))d=c.outline.sections[0]}if(a.nextSibling){a=a.nextSibling;continue a}a=
a==b?null:a.parentNode}}return null!=c?c.outline:null}})();


    var outline = HTML5Outline(document.body);
    document.getElementById('toc').innerHTML =
        outline.asHTML({createLinks: true, skipTopHeader: true, skipUntitled: true});
  //--></script>
</body>
</html>
