<!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_ref: a non-owning reference to a string, revision 2</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: 1em}
section header {margin-left: -1em}

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 { border: double; margin: 1em; border-collapse: collapse; }
caption { white-space: pre; }
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>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">//<![CDATA[
$(function() {
    var next_id = 0
    function find_id(node) {
        // Look down the first children of 'node' until we find one
        // with an id. If we don't find one, give 'node' an id and
        // return that.
        var cur = node[0];
        while (cur) {
            if (cur.id) return cur.id;
            if (cur.tagName == 'A' && cur.name)
                return cur.name;
            cur = cur.firstChild;
        };
        // No id.
        node.attr('id', 'gensection-' + next_id++);
        return node.attr('id');
    };

    // Put a table of contents in the #toc nav.

    // This is a list of <ol> elements, where toc[N] is the list for
    // the current sequence of <h(N+2)> tags. When a header of an
    // existing level is encountered, all higher levels are popped,
    // and an <li> is appended to the level
    var toc = [$("<ol/>")];
    $(':header').not('h1').each(function() {
        var header = $(this);
        // For each <hN> tag, add a link to the toc at the appropriate
        // level.  When toc is one element too short, start a new list
        var levels = {H2: 0, H3: 1, H4: 2, H5: 3, H6: 4};
        var level = levels[this.tagName];
        if (typeof level == 'undefined') {
            throw 'Unexpected tag: ' + this.tagName;
        }
        // Truncate to the new level.
        toc.splice(level + 1, toc.length);
        if (toc.length < level) {
            // Omit TOC entries for skipped header levels.
            return;
        }
        if (toc.length == level) {
            // Add a <ol> to the previous level's last <li> and push
            // it into the array.
            var ol = $('<ol/>')
            toc[toc.length - 1].children().last().append(ol);
            toc.push(ol);
        }
        var header_text = header.text();
        toc[toc.length - 1].append(
            $('<li/>').append($('<a href="#' + find_id(header) + '"/>')
                              .text(header_text)));
    });
    $('#toc').append(toc[0]);
})
//]]></script>
</head>
<body>
  <header>
    <div class="docinfo">
      <p>ISO/IEC JTC1 SC22 WG21 N3512</p>
      <p>Date: <time pubdate="">2013-01-11</time></p>
      <address>
        <p>Jeffrey Yasskin &lt;<a href="mailto:jyasskin@google.com">jyasskin@google.com</a>&gt;</p>
      </address>
    </div>
    <h1><code>string_ref</code>: a non-owning reference to a string, revision 2</h1>
  </header>
  <p><small><a href="#maincontent">Skip table of contents</a></small></p>
  <nav id="toc"></nav>
  <a id="maincontent"></a>
  <section>
    <header><h2 id="overview">Overview</h2></header>
    <p>This paper updates <a
    href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3334.html">N3334</a>
    (<code>string_ref</code> + <code>array_ref</code>) and <a
    href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html">N3442</a>
    (<code>string_ref</code> for a TS) 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.  The <a
    href="https://github.com/google/cxx-std-draft/blob/string-ref-paper/string_ref.html">most
    recent version of this paper</a> is maintained on GitHub.</p>

    <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.ref"><code>string_ref</code></a> is implicitly
    constructible from <code>const char*</code> and <code>std::string</code>. It
    provides most of 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/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_ref</code> to <code><a
    href="#basic.string.ref">basic_string_ref</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_ref</code> types (but not
    Bloomberg's) extend the interface from <code>std::string</code> to provide
    some helpful utility functions:</p>
    <ul>
      <li><a href="#string.ref.ops">starts_with</a></li>
      <li><a href="#string.ref.ops">ends_with</a></li>
      <li><a href="#string.ref.modifiers">remove_prefix</a></li>
      <li><a href="#string.ref.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_ref</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><a href="#string.conversions">numeric conversions</a></li>
    </ul>
  </section>

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

    <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.ref.nonmem"><code>to_string</code> function</a>.</p>

    <p>Google's and LLVM's <code>string_ref</code> types provide a subset of
    <code>std::string</code>'s searching operations, but they do provide
    <code>pos</code> arguments to specify where to start the search. Because <a
    href="#string.ref.ops"><code>string_ref::substr</code></a> is
    much cheaper than <code>string::substr</code>, this paper removes the
    <code>pos</code> argument entirely.</p>

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

  <section>
    <header><h2 id="bikeshed">Bikeshed!</h2></header>
    <p><a
    href="https://groups.google.com/a/isocpp.org/d/topic/std-proposals/5sW8yp5i8mo/discussion">Consensus
    seems to be developing around renaming this class to
    <code>string_view</code>.</a> If that keeps up, the next revision of this
    paper will incorporate that change.  Other options include:</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>
    <header><h2 id="modifications">Modifications vs std::string</h2></header>

    <p>The interface of <code>string_ref</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_ref</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">Additions</h3>
    <ul>
      <li><code><a
      href="#string.ref.modifiers">remove_prefix()</a></code> and
      <code><a
      href="#string.ref.modifiers">remove_suffix()</a></code> make
      it easy to parse strings using <code>string_ref</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>

      <li><a href="#string.ref.ops">starts_with</a> and <a
      href="#string.ref.ops">ends_with</a> are common queries on
      strings.  The non-member equivalents produce calls that are somewhat
      ambiguous between <code>starts_with(haystack, needle)</code> vs
      <code>starts_with(needle, haystack)</code>, while
      <code>haystack.starts_with(needle)</code> is the only English reading of
      the member version.  These queries apply equally well to
      <code>basic_string</code>, so I've <a
      href="#string.starts.ends.with">added them there too</a>.</li>
    </ul>

    <h3 id="removals">Removals</h3>
    <ul>
      <li>The <code>copy</code> method has been removed from
      <code>string_ref</code>.  <code>std::string::copy</code> is copy
      <em>out</em>, not in.  It's not well named.  Users can easily use
      <code>std::copy</code> instead.</li>

      <li><code>pos</code> and <code>n</code> parameters to methods have been
      removed from <code>string_ref</code>.  <code>std::string</code> needs
      these parameters because <code>std::string::substring</code> is an
      expensive (copying and sometimes allocating) operation.  However, these
      are always integral parameters, so the compiler can't check that their
      order is correct, and readers often have a hard time.  Because <code><a
      href="#string.ref.ops">string_ref::substr</a></code> is cheap,
      we insist users call it instead of passing its arguments to other
      functions.</li>
    </ul>

  </section>

  <section>
    <header><h2 id="lib-modifications">Modifications to the rest of the standard library</h2></header>
    <p>This paper makes
    <code>char_traits::</code>{<code>length</code>,<code>find</code>,<code>compare</code>}
    <code>constexpr</code> so that <code>basic_string_ref</code> can be
    constructed from string literals at compile time and so that
    <code>basic_string_ref::</code>{<code>find</code>,<code>compare</code>,<code>operator==</code>,
    etc.}  can be <code>constexpr</code>.  This implements the proposed
    resolution for <a
    href="http://cplusplus.github.com/LWG/lwg-active.html#2232">LWG Issue
    2232</a>.  An alternate way to get compile-time <code>string_ref</code>s
    would be to define a user-defined literal operator a'la <a
    href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3468.pdf">N3468</a>. Arguably,
    <code>basic_string_ref</code> is a better candidate for the <code>""s</code>
    suffix than <code>basic_string</code> since <code>basic_string</code> isn't
    a literal type.</p>

    <p>When deciding which functions to add <code>basic_string_ref</code>
    overloads to, I followed the following rules:</p>
    <ul>
      <li>If the function already had overloads for <code>const char*</code> and
      <code>basic_string</code>, I added a <code>basic_string_ref</code>
      overload.</li>

      <li>If the function had a <code>basic_string</code> overload but not a
      <code>const char*</code> overload, and <code>const char*</code> arguments
      could not be passed with an implicit conversion (generally because
      template argument deduction would fail), I added a
      <code>basic_string_ref</code> overload.</li>

      <li>If the function had a <code>basic_string</code> overload but not a
      <code>const char*</code> overload, and <code>const char*</code> arguments
      <em>could</em> be passed with an implicit conversion, then I did not add a
      <code>basic_string_ref</code> overload, on the theory that copies are
      already expected and cheap enough, and because adding a
      <code>basic_string_ref</code> overload would require also adding a
      <code>const char*</code> overload to avoid breaking user code.</li>
    </ul>

    <p>I didn't add <code>basic_string_ref</code> overloads to a few functions
    where this would be hard to implement:</p>

    <ul>
      <li>The locale <code>_byname</code> facets are implemented on Unix by forwarding
      to a C library function that takes a <code>'\0'</code>-terminated string,
      with no option to pass a length.  Since accepting a
      <code>string_ref</code> would require a copy regardless, users may as well
      pass a <code>string</code>.</li>

      <li>Several locale facet methods take <code>basic_string</code>, and
      forward the argument on to a virtual method. Defining a version taking
      <code>basic_string_ref</code>, even with a default implementation
      forwarding to the <code>string</code> version, would break user subclasses
      because of a common compiler warning that fires when a virtual method is
      hidden.  This propagates to the <code>put_money</code> I/O manipulator.</li>
    </ul>

    <p>I also omitted <code>operator+(basic_string, basic_string_ref)</code>
    because LLVM returns a lightweight object from this overload and only
    performs the concatenation lazily.  If we define this overload, we'll have a
    hard time introducing that lightweight concatenation later.</p>

    <p id="no-fix-2216">Following the <code>basic_string</code> and <code>const
    char*</code> overloads of <code>regex_replace()</code>, the
    <code>string_ref</code> overloads don't let the user specify an explicit
    allocator.  This should be fixed with the resolution to <a
    href="http://cplusplus.github.com/LWG/lwg-active.html#2216">issue 2216</a>.
    I believe you have enough to read in this paper as it is and that it would
    be unwise to jam a fix into here.</p>
  </section>

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

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

      <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_ref</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>
    </section>

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

      <p>… and use <code>basic_string_ref&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_ref</code> parameters,
      which would defeat a significant use case for <code>string_ref</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_ref</code>.</p>

      <p>We <em>could</em> use <code>typedef basic_string_ref&lt;const char>
      string_ref</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>
      <header><h3 id="operator-bool">Add an <code>explicit operator bool</code></h3></header>

      <p>This would be an abbreviation for <code>!empty()</code>, usable for
      initialization in <code>if</code> statements.  I didn't add this because
      it would be inconsistent with the rest of the containers library, but if
      another proposal adds it to the rest of the containers, that proposal
      should also add it to <code>string_ref</code>.</p>
    </section>

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

      <p>With a constructor of the form:</p>
      <pre class="example"><code>template&lt;size_t N>
basic_string_ref(const charT (&amp;str)[N]);</code></pre>
      <p>we could avoid a <code>strlen()</code> call when a
      <code>basic_string_ref</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_ref str(space);</code></pre>
      <p>I don't know any way to distinguish string literals from local arrays,
      so the only way to be safe is to call <code>strlen()</code> on array
      arguments.  Some people have suggested a
      <code>string_ref::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 safe code as efficient as the template.  Other implementations should
      provide the same optimization as a QoI issue.</p>
    </section>

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

      <p>Operations on <code>string_ref</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_ref</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>
      <header><h3 id="contiguous-range">Wait for <code>contiguous_range&lt;charT></code></h3></header>

      <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_ref</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_ref</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_ref</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>
      <header><h3 id="null-termination">Make <code>string_ref</code> null-terminated</h3></header>

      <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_ref</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_ref</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_ref</code>
      class to represent null-terminated strings and let it decay to
      <code>string_ref</code> when necessary.  That's plausible but not part of
      this proposal.</p>
    </section>

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

      <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>
      <header><h3 id="data-size-constructor">Allow implicit conversion from more types.</h3></header>

      <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_ref_{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>
    </section>
  </section>

  <section>
    <header><h2 id="questions">Open Questions</h2></header>
    <p>How does this interact with <a
    href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3456.html">N3456</a>?
    Several <code>basic_string_ref</code> overloads would be handled by the
    <code>Range&&</code> arguments that N3456 adds, and several more (e.g. in
    <code>&lt;regex></code>) would be handled by extending those template
    arguments to the rest of the library. In non-deducing contexts,
    <code>basic_string_ref</code> can serve as an implicit conversion target, so we want it
    anyway, but in deducing context, I think the <code>Range&&</code> argument is strictly
    better.</p>
  </section>

  <hr/>

  <section class="wording">
    <header><h2 id="wording">Wording</h2></header>

    <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="library">Clause 17, Library introduction</h3>

    <h4>Modify the note in [defns.component]</h4>
    <p>For example, the class <del>template </del><ins>templates
    </ins>basic_string <ins>and basic_string_ref </ins>and the non-member
    function templates that operate on strings are referred to as the
    <dfn>string component</dfn>.</p>

    <h3 id="utilities">Clause 20, General utilities library</h3>

    <h4>Add a constructor to class bitset in [template.bitset]</h4>
<pre><code>template&lt;class charT, class traits>
  explicit bitset(
    basic_string_ref&lt;charT,traits> str,
    charT zero = charT(’0’), charT one = charT(’1’));</code></pre>

    <h4>Modify the constructor definitions in [bitset.cons]</h4>

<pre><code>template &lt;class charT, class traits, class Allocator>
explicit
bitset(const basic_string&lt;charT, traits, Allocator>& str,
       typename basic_string&lt;charT, traits, Allocator>::size_type pos = 0,
       typename basic_string&lt;charT, traits, Allocator>::size_type n =
         basic_string&lt;charT, traits, Allocator>::npos,
       charT zero = charT(’0’), charT one = charT(’1’));</code></pre>
<div class="attributes">
<p><ins><i>Effects:</i> Equivalent to <code>bitset(basic_string_ref&lt;charT, traits>(str).substr(pos, n),
zero, one)</code></ins></p>
</div>

<pre><code><ins>template &lt;class charT, class traits>
explicit
bitset(basic_string_ref&lt;charT, traits> str,
       charT zero = charT(’0’), charT one = charT(’1’));</ins></code></pre>

<div class="attributes">
<p><del><i>Requires:</i> <code>pos &lt;= str.size()</code>.</del></p>

<p><del><i>Throws:</i> <code>out_of_range</code> if <code>pos > str.size()</code>.</del></p>

<p><del><i>Effects:</i> Determines the effective length <code><var>rlen</var></code> of the initializing string as the smaller of <code>n</code> and <code>str.size() - pos</code>.</del></p>

<p><del>The function then throws </del><ins><i>Throws:</i>
</ins><code>invalid_argument</code> if any of the <del>rlen </del>characters in
<code>str</code> <del>beginning at position pos </del>is other than zero or one. The function
uses <code>traits::eq()</code> to compare the character values.</p>

<p><del>Otherwise, the </del><ins><i>Effects:</i> </ins>function
constructs an object of class <code>bitset&lt;N></code>, initializing
the first <code>M</code> bit positions to values determined from the
corresponding characters in the string
<code>str</code>. <code>M</code> is the smaller of <code>N</code> and
<code><del>rlen</del><ins>str.size()</ins></code>.</p>

<p>An element of the constructed string has value zero if the corresponding
character in <code>str</code>, <del>beginning at position pos, </del>is <del>0
</del><code>zero</code>. Otherwise, the element has the value 1. Character
position <code>pos <del>+ M </del>- 1</code> corresponds to bit position
zero. Subsequent decreasing character positions correspond to increasing bit
positions.</p>

<p>If <code>M &lt; N</code>, remaining bit positions are initialized to zero.</p>
</div>

<pre><code>template &lt;class charT>
  explicit bitset(
    const charT* str,
    typename basic_string&lt;charT>::size_type n = basic_string&lt;charT>::npos,
    charT zero = charT(’0’), charT one = charT(’1’));</code></pre>

<div class="attributes">
<p><i>Effects:</i> Constructs an object of class bitset&lt;N> as if by</p>
<pre><code>bitset(
  n == basic_string&lt;charT>::npos
    ? basic_string<ins>_ref</ins>&lt;charT>(str)
    : basic_string<ins>_ref</ins>&lt;charT>(str, n),
  <del>0, n, </del>zero, one)</code></pre>
</div>

    <h3 id="strings">Clause 21, Strings library</h3>

    <h4>Modify [char.traits.specializations.char], [char.traits.specializations.char16_t], [char.traits.specializations.char32_t], and [char.traits.specializations.wchar.t]</h4>

    <div class="ednote"><p>This implements the proposed resolution of <a
    href="">LWG issue ####</a>.  I could take it out at the cost of making
    <code>basic_string_ref(const charT*)</code> and all of the comparison
    operators and methods non-<code>constexpr</code>.</p></div>

<pre><code>static <ins>constexpr </ins>int compare(const char_type* s1, const char_type* s2, size_t n);
static <ins>constexpr </ins>size_t length(const char_type* s);
static <ins>constexpr </ins>const char_type* find(const char_type* s, size_t n,
                                       const char_type& a);</code></pre>

    <h4 id="strings.string_ref.header">Modify [string.classes]</h4>

    <p>The header &lt;string> defines the basic_string class template for manipulating
    varying-length sequences of char-like objects and four typedefs, string,
    u16string, u32string, and wstring, that name the specializations
    basic_string&lt;char>, basic_string&lt;char16_t>, basic_string&lt;char32_t>, and
    basic_string&lt;wchar_t>, respectively.</p>

    <p><ins>&lt;string> also defines the <code>basic_string_ref</code> class
    template for referring to constant sequences of char-like objects and four
    typedefs, <code>string_ref</code>, <code>u16string_ref</code>,
    <code>u32string_ref</code>, and <code>wstring_ref</code>, that name the
    specializations <code>basic_string_ref&lt;char></code>,
    <code>basic_string_ref&lt;char16_t></code>,
    <code>basic_string_ref&lt;char32_t></code>, and
    <code>basic_string_ref&lt;wchar_t></code>, respectively.</ins></p>

    <h4>Add to the appropriate places within "Header &lt;string> synopsis"</h4>

    <pre><code>  // [basic.string.ref], basic_string_ref:
  template&lt;class charT, class traits = char_traits&lt;charT>>
      class basic_string_ref;

  // [string.ref.comparison], non-member basic_string_ref comparison functions
  template&lt;typename charT, typename traits>
  bool operator==(basic_string_ref&lt;charT, traits> x, basic_string_ref&lt;charT, traits> y);
  template&lt;typename charT, typename traits>
  bool operator!=(basic_string_ref&lt;charT, traits> x, basic_string_ref&lt;charT, traits> y);
  template&lt;typename charT, typename traits>
  bool operator&lt; (basic_string_ref&lt;charT, traits> x, basic_string_ref&lt;charT, traits> y);
  template&lt;typename charT, typename traits>
  bool operator> (basic_string_ref&lt;charT, traits> x, basic_string_ref&lt;charT, traits> y);
  template&lt;typename charT, typename traits>
  bool operator&lt;=(basic_string_ref&lt;charT, traits> x, basic_string_ref&lt;charT, traits> y);
  template&lt;typename charT, typename traits>
  bool operator>=(basic_string_ref&lt;charT, traits> x, basic_string_ref&lt;charT, traits> y);
  // Sufficient additional overloads to allow mixed comparisons with any type
  // that has an implicit conversion to basic_string_ref&lt;charT, traits>.

  // [string.ref.nonmem], other non-member basic_string_ref 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_ref&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_ref&lt;charT,traits> str);

  // basic_string_ref typedef names
  typedef basic_string_ref&lt;char> string_ref;
  typedef basic_string_ref&lt;char16_t> u16string_ref;
  typedef basic_string_ref&lt;char32_t> u32string_ref;
  typedef basic_string_ref&lt;wchar_t> wstring_ref;</code></pre>

    <div class="ednote">
      <p>It would be nice to remove the <code>string</code> overloads for the
      numeric conversion functions, but that could break code that relies on an
      implicit conversion to string.  Instead, we need to add <code>const
      char*</code> overloads to avoid ambiguity.</p>

      <p>I'd also like to add <code>optional&lt;T>
      sto<var>x</var>_consume(string_ref&, int base=10)</code> if/when
      <code>optional</code> becomes available.</p>
    </div>

<pre><code>  int stoi(string_ref str, size_t* idx = 0, int base = 10);
  int stoi(const char* str, size_t* idx = 0, int base = 10);
  long stol(string_ref str, size_t* idx = 0, int base = 10);
  long stol(const char* str, size_t* idx = 0, int base = 10);
  unsigned long stoul(string_ref str, size_t* idx = 0, int base = 10);
  unsigned long stoul(const char* str, size_t* idx = 0, int base = 10);
  long long stoll(string_ref str, size_t* idx = 0, int base = 10);
  long long stoll(const char* str, size_t* idx = 0, int base = 10);
  unsigned long long stoull(string_ref str, size_t* idx = 0, int base = 10);
  unsigned long long stoull(const char* str, size_t* idx = 0, int base = 10);
  float stof(string_ref str, size_t* idx = 0);
  float stof(const char* str, size_t* idx = 0);
  double stod(string_ref str, size_t* idx = 0);
  double stod(const char* str, size_t* idx = 0);
  long double stold(string_ref str, size_t* idx = 0);
  long double stold(const char* str, size_t* idx = 0);

  int stoi(wstring_ref str, size_t* idx = 0, int base = 10);
  int stoi(const wchar_t* str, size_t* idx = 0, int base = 10);
  long stol(wstring_ref str, size_t* idx = 0, int base = 10);
  long stol(const wchar_t* str, size_t* idx = 0, int base = 10);
  unsigned long stoul(wstring_ref str, size_t* idx = 0, int base = 10);
  unsigned long stoul(const wchar_t* str, size_t* idx = 0, int base = 10);
  long long stoll(wstring_ref str, size_t* idx = 0, int base = 10);
  long long stoll(const wchar_t* str, size_t* idx = 0, int base = 10);
  unsigned long long stoull(wstring_ref str, size_t* idx = 0, int base = 10);
  unsigned long long stoull(const wchar_t* str, size_t* idx = 0, int base = 10);
  float stof(wstring_ref str, size_t* idx = 0);
  float stof(const wchar_t* str, size_t* idx = 0);
  double stod(wstring_ref str, size_t* idx = 0);
  double stod(const wchar_t* str, size_t* idx = 0);
  long double stold(wstring_ref str, size_t* idx = 0);
  long double stold(const wchar_t* str, size_t* idx = 0);

  template &lt;> struct hash&lt;string_ref>;
  template &lt;> struct hash&lt;u16string_ref>;
  template &lt;> struct hash&lt;u32string_ref>;
  template &lt;> struct hash&lt;wstring_ref>;</code></pre>

    <h4 id="basic.string.ref">Add a subclause "x.y Class template
    basic_string_ref [basic.string.ref]"</h4>

    <p>The class template basic_string_ref describes objects that can refer to a
    constant sequence of arbitrary char-like 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 basic_string_ref object is designated by
    charT.</p>

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

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


     <pre><code>namespace std {
  template&lt;typename charT, typename traits = char_traits&lt;charT>>
  class basic_string_ref {
    public:
    // types
    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.ref.iterators]
    typedef const_iterator iterator;  // [Footnote: Because basic_string_ref refers to a constant sequence, iterator and const_iterator are the same type. --end footnote]
    typedef std::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.ref.cons], construct/copy
    constexpr basic_string_ref() noexcept;
    constexpr basic_string_ref(const basic_string_ref&) noexcept = default;
    basic_string_ref& operator=(const basic_string_ref&) noexcept = default;
    constexpr basic_string_ref(const charT* str);
    constexpr basic_string_ref(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 string_ref.</p></div>

<pre><code>    // [string.ref.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.ref.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.ref.access], element access
    constexpr const charT& operator[](size_type pos) const;
    const charT& at(size_t pos) const;
    constexpr const charT& front() const;
    constexpr const charT& back() const;
    constexpr const charT* data() const noexcept;

    // [string.ref.modifiers], modifiers:
    void clear() noexcept;
    void remove_prefix(size_type n);
    void remove_suffix(size_type n);

    // [string.ref.ops], string operations:
    constexpr basic_string_ref substr(size_type pos, size_type n=npos) const;
    constexpr int compare(basic_string_ref s) const noexcept;
    constexpr int compare(const charT* s) const noexcept;
    constexpr bool starts_with(basic_string_ref s) const noexcept;
    constexpr bool starts_with(charT c) const noexcept;
    constexpr bool starts_with(const charT* s) const noexcept;
    constexpr bool ends_with(basic_string_ref s) const noexcept;
    constexpr bool ends_with(charT c) const noexcept;
    constexpr bool ends_with(const charT* s) const noexcept;
    size_type find(basic_string_ref s) const noexcept;
    size_type find(charT c) const noexcept;
    size_type find(const charT* s) const noexcept;
    size_type rfind(basic_string_ref s) const noexcept;
    size_type rfind(charT c) const noexcept;
    size_type rfind(const charT* s) const noexcept;
    size_type find_first_of(basic_string_ref s) const noexcept;
    size_type find_first_of(charT c) const noexcept;
    size_type find_first_of(const charT* s) const noexcept;
    size_type find_last_of(basic_string_ref s) const noexcept;
    size_type find_last_of(charT c) const noexcept;
    size_type find_last_of(const charT* s) const noexcept;
    size_type find_first_not_of(basic_string_ref s) const noexcept;
    size_type find_first_not_of(charT c) const noexcept;
    size_type find_first_not_of(const charT* s) const noexcept;
    size_type find_last_not_of(basic_string_ref s) const noexcept;
    size_type find_last_not_of(charT c) const noexcept;
    size_type find_last_not_of(const charT* s) const noexcept;
};</code></pre>

    <p>Each member function of the form</p>
    <pre><code>rt fx1(const charT* s); // such as compare(), find()</code></pre>
    <p>is equivalent to <code>fx1(basic_string_ref(s))</code>.</p>

    <p>Each member function of the form</p>
    <pre><code>rt fx2(charT c); // such as starts_with(), find()</code></pre>
    <p>is equivalent to <code>fx2(basic_string_ref(&c, 1))</code>.</p>

    <h5>Add a sub-subclause "x.y.1 basic_string_ref constructors and assignment operators  [string.ref.cons]"</h5>

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

    <pre><code>basic_string_ref(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_ref referring to the same string as str, with the postconditions
      in Table [tab:string.ref.ctr.1]</p>

      <table><caption>Table [tab:string.ref.ctr.1] — basic_string_ref(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_ref(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_ref, with the postconditions in Table [tab:string.ref.ctr.2]</p>
      <table><caption>Table [tab:string.ref.ctr.2] — basic_string_ref(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>


    <h5>Add a sub-subclause "x.y.2 basic_string_ref iterator support [string.ref.iterators]"</h5>

    <pre><code>typedef implementation-defined const_iterator;</code></pre>
    <div class="attributes">
      <p>A random-access, contiguous iterator type.</p>
      <p>For a basic_string_ref 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>
    </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>

    <h5>Add a sub-subclause "x.y.3 basic_string_ref capacity [string.ref.capacity]"</h5>

    <pre><code>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 string_ref.</p>
      <p><i>Complexity</i>: constant time.</p>
    </div>

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

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

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


    <h5>Add a sub-subclause "x.y.4 basic_string_ref element access [string.ref.access]"</h5>

    <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_ref::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 operator[](0).</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 operator[](size() - 1).</p>
    </div>

    <pre><code>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>

    <h5 id="string.ref.modifiers">Add a sub-subclause "x.y.5 basic_string_ref modifiers [string.ref.modifiers]"</h5>

    <pre><code>void clear() noexcept;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>*this = basic_string_ref()</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>


    <h5 id="string.ref.ops">Add a sub-subclause "x.y.6 basic_string_ref string operations [string.ref.ops]"</h5>

    <p>[ Note: Unlike std::basic_string, std::basic_string_ref provides no
    whole-string methods with posi- tion or length parameters. Instead, users
    should use the substr() method to create the character sequence they’re
    actually interested in, and use that. — end note ]</p>

    <pre><code>basic_string_ref substr(size_type pos, 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_ref(data()+pos, rlen).</p>
    </div>

    <pre><code>int compare(const basic_string_ref& 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.ref.compare].</p>
      <table><caption>Table [tab:string.ref.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>bool starts_with(const basic_string_ref& prefix) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Complexity</i>: O(min(size(), prefix.size()))</p>
      <p><i>Returns</i>: <code>size() >= prefix.size() &&<wbr/> substr(0, prefix.size()) == prefix</code></p>
    </div>

    <pre><code>bool ends_with(const basic_string_ref& suffix) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Complexity</i>: O(min(size(), suffix.size()))</p>
      <p><i>Returns</i>: <code>size() >= suffix.size() &&<wbr/> substr(size() - suffix.size(), npos) == suffix</code></p>
    </div>

    <h6>Add a sub<sup>3</sup>clause "x.y.6.1 Searching basic_string_ref [string.ref.find]"</h6>

    <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(const basic_string_ref& str) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the lowest position xpos, if possible, such that both of the following conditions obtain:</p>
      <ul><li>xpos + str.size() <= 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(const basic_string_ref& str) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the highest position xpos, if possible, such that both of the following conditions obtain:</p>
      <ul><li>xpos + str.size() <= 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(const basic_string_ref& str) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the lowest position xpos, if possible, such that both of the following conditions obtain:</p>
      <ul><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(const basic_string_ref& str) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the highest position xpos, if possible, such that both of the following conditions obtain:</p>
      <ul><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(const basic_string_ref& str) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the lowest position xpos, if possible, such that both of the following conditions obtain:</p>
      <ul><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(const basic_string_ref& str) const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Determines the highest position xpos, if possible, such that both of the following conditions obtain:</p>
      <ul><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>


    <h5>Add a sub-subclause "x.y.7 basic_string_ref non-member comparison functions [string.ref.comparison]"</h5>

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

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

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

<pre><code>template&lt;class charT, class traits>
  bool operator==(basic_string_ref&lt;charT,traits> lhs,
                  basic_string_ref&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_ref&lt;charT,traits> lhs,
                  basic_string_ref&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_ref&lt;charT,traits> lhs,
                  basic_string_ref&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_ref&lt;charT,traits> lhs,
                  basic_string_ref&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_ref&lt;charT,traits> lhs,
                  basic_string_ref&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_ref&lt;charT,traits> lhs,
                  basic_string_ref&lt;charT,traits> rhs) noexcept;</code></pre>
    <p class="attribute"><i>Returns</i>: lhs.compare(rhs) >= 0.</p>

    <h5 id="string.ref.nonmem">Add a sub-subclause "x.y.8 Other basic_string_ref non-member functions [string.ref.nonmem]"</h5>

    <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_ref&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, a).</p>
    </div>

    <h4>Add to the appropriate places within the class definition of [basic.string]</h4>
<pre><code>    explicit // Footnote: This conversion is explicit to avoid accidental O(N) operations on type mismatches. --end footnote
    basic_string(basic_string_ref&lt;charT, traits>,
                 const Allocator& = Allocator());
    basic_string& operator=(basic_string_ref&lt;charT, traits>);
    basic_string& operator+=(basic_string_ref&lt;charT, traits>);
    basic_string& append(basic_string_ref&lt;charT, traits>);
    basic_string& assign(basic_string_ref&lt;charT, traits>);
    basic_string& replace(const_iterator, const_iterator, basic_string_ref&lt;charT, traits>);
    operator basic_string_ref&lt;charT, traits>() const noexcept;
    bool starts_with(basic_string_ref&lt;charT, traits> s) const noexcept;
    bool starts_with(charT c) const noexcept;
    bool starts_with(const charT* s) const noexcept;
    bool ends_with(basic_string_ref&lt;charT, traits> s) const noexcept;
    bool ends_with(charT c) const noexcept;
    bool ends_with(const charT* s) const noexcept;</code></pre>

    <h4 id="string.cons">Add to [string.cons]</h4>
    <pre><code>explicit basic_string(basic_string_ref&lt;charT, traits> str, const Allocator& a = Allocator());</code></pre>
    <p class="attribute"><i>Effects</i>: Same as basic_string(str.begin(), str.end(), a).</p>
    <div class="ednote"><p>This uses "Same as" instead of "Equivalent to" to be consistent with the rest of the basic_string specification.</p></div>

    <h4>Add to [string.accessors]</h4>
    <pre><code>operator basic_string_ref&lt;charT, traits>() const noexcept;</code></pre>
    <div class="attributes">
      <p><i>Returns</i>: basic_string_ref&lt;charT, traits>(data(), size()).</p>
      <p><i>Complexity</i>: constant time.</p>
      <p><i>Requires</i>: The program shall not alter any of the values stored in the character array.</p>
    </div>

    <h4 id="string.starts.ends.with">Add a section "basic_string::starts_with and ends_with [string.starts.ends.with]" inside [string.ops]</h4>

    <pre><code>bool starts_with(const basic_string_ref&lt;charT, traits>& prefix) const noexcept;
bool starts_with(charT prefix) const noexcept;
bool starts_with(const charT* prefix) const noexcept;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>basic_string_ref&lt;charT, traits>(*this).starts_with(prefix)</code></p>

    <pre><code>bool ends_with(const basic_string_ref&lt;charT, traits>& suffix) const noexcept;
bool ends_with(charT suffix) const noexcept;
bool ends_with(const charT* suffix) const noexcept;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>basic_string_ref&lt;charT, traits>(*this).ends_with(suffix)</code></p>

    <h4>Move [string.io] directly under [strings] and modify it</h4>

    <pre><code>template&lt;class charT, class traits, class Allocator>
  basic_ostream&lt;charT, traits>&
    operator&lt;&lt;(basic_ostream&lt;charT, traits>& os,
               const basic_string&lt;charT,traits,Allocator>& str);
<ins>template&lt;class charT, class traits, class Allocator>
  basic_ostream&lt;charT, traits>&
    operator&lt;&lt;(basic_ostream&lt;charT, traits>& os,
               basic_string_ref&lt;charT,traits> str);</ins></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="string.conversions">Add to [string.conversions]</h4>
    <pre><code>int stoi(string_ref str, size_t *idx = 0, int base = 10);
long stol(string_ref str, size_t *idx = 0, int base = 10);
unsigned long stoul(string_ref str, size_t *idx = 0, int base = 10);
long long stoll(string_ref str, size_t *idx = 0, int base = 10);
unsigned long long stoull(string_ref str, size_t *idx = 0, int base = 10);
float stof(string_ref str, size_t *idx = 0);
double stod(string_ref str, size_t *idx = 0);
long double stold(string_ref str, size_t *idx = 0);

int stoi(const char* str, size_t *idx = 0, int base = 10);
long stol(const char* str, size_t *idx = 0, int base = 10);
unsigned long stoul(const char* str, size_t *idx = 0, int base = 10);
long long stoll(const char* str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const char* str, size_t *idx = 0, int base = 10);
float stof(const char* str, size_t *idx = 0);
double stod(const char* str, size_t *idx = 0);
long double stold(const char* str, size_t *idx = 0);</code></pre>

    <div class="attributes">
      <p>Each function of the forms</p>
      <pre><code>  rt fn(string_ref str, size_t *idx = 0, int base = 10);
  rt fn(const char* str, size_t *idx = 0, int base = 10);</code></pre>
      <p>is equivalent to <code>fn(string(str), idx, base)</code>.</p>

      <p>Each function of the forms</p>
      <pre><code>  rt fn(string_ref str, size_t *idx = 0);
  rt fn(const char* str, size_t *idx = 0);</code></pre>
      <p>is equivalent to <code>fn(string(str), idx)</code>.</p>
</div>

<pre><code>int stoi(wstring_ref str, size_t *idx = 0, int base = 10);
long stol(wstring_ref str, size_t *idx = 0, int base = 10);
unsigned long stoul(wstring_ref str, size_t *idx = 0, int base = 10);
long long stoll(wstring_ref str, size_t *idx = 0, int base = 10);
unsigned long long stoull(wstring_ref str, size_t *idx = 0, int base = 10);
float stof(wstring_ref str, size_t *idx = 0);
double stod(wstring_ref str, size_t *idx = 0);
long double stold(wstring_ref str, size_t *idx = 0);

int stoi(const wchar_t* str, size_t *idx = 0, int base = 10);
long stol(const wchar_t* str, size_t *idx = 0, int base = 10);
unsigned long stoul(const wchar_t* str, size_t *idx = 0, int base = 10);
long long stoll(const wchar_t* str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const wchar_t* str, size_t *idx = 0, int base = 10);
float stof(const wchar_t* str, size_t *idx = 0);
double stod(const wchar_t* str, size_t *idx = 0);
long double stold(const wchar_t* str, size_t *idx = 0);</code></pre>

    <div class="attributes">
      <p>Each function of the forms</p>
      <pre><code>  rt fn(wstring_ref str, size_t *idx = 0, int base = 10);
  rt fn(const wchar_t* str, size_t *idx = 0, int base = 10);</code></pre>
      <p>is equivalent to <code>fn(wstring(str), idx, base)</code>.</p>

      <p>Each function of the forms</p>
      <pre><code>  rt fn(wstring_ref str, size_t *idx = 0);
  rt fn(const wchar_t* str, size_t *idx = 0);</code></pre>
      <p>is equivalent to <code>fn(wstring(str), idx)</code>.</p>
    </div>


    <h4 id="basic.string.hash">Modify [basic.string.hash]</h4>

    <pre><code><ins>template &lt;> struct hash&lt;string_ref>;
template &lt;> struct hash&lt;u16string_ref>;
template &lt;> struct hash&lt;u32string_ref>;
template &lt;> struct hash&lt;wstring_ref>;</ins>
template &lt;> struct hash&lt;string>;
template &lt;> struct hash&lt;u16string>;
template &lt;> struct hash&lt;u32string>;
template &lt;> struct hash&lt;wstring>;</code></pre>
    <p class="attribute"><i>Requires</i>: the template specializations shall
    meet the requirements of class template hash ([unord.hash]).</p>


    <h3 id="localization">Clause 22, Localization library</h3>

    <h4>Modify a note in [locale]</h4>
    <p>[ Note: All locale semantics are accessed via use_facet&lt;> and has_facet&lt;>, except that:</p>
    <ul>
      <li><del>A member operator template </del><ins>Two member operator
      templates </ins>operator()(const basic_string&lt;C, T, A>&, const
      basic_string&lt;C, T, A>&) <del>is </del><ins>and operator()(const
      basic_string_ref&lt;C, T>&, const basic_string_ref&lt;C, T>&) are
      </ins>provided so that a locale may be used as a predicate argument to the
      standard collections, to collate strings.</li>
      <li>Convenient global interfaces are provided for traditional ctype
      functions such as isdigit() and isspace(), so that given a locale object
      loc a C++ program can call isspace(c,loc). (This eases upgrading existing
      extractors (27.7.2.2).) — end note ]</li>
    </ul>


    <h4>Modify [locale.operators]</h4>
<pre><code>template &lt;class charT, class traits, class Allocator>
  bool operator()(const basic_string&lt;charT,traits,Allocator>& s1,
                  const basic_string&lt;charT,traits,Allocator>& s2) const;
<ins>template &lt;class charT, class traits>
  bool operator()(const basic_string_ref&lt;charT,traits>& s1,
                  const basic_string_ref&lt;charT,traits>& s2) const;</ins></code></pre>

    <div class="attributes">
      <p><i>Effects</i>: Compares two strings according to the collate&lt;charT> facet.</p>
      <p><i>Remarks</i>: This member operator template (and therefore locale itself)
      satisfies requirements for a comparator predicate template argument (Clause 25)
      applied to strings.</p>
      <p><i>Returns</i>: The result of the following expression:
      <code>use_facet&lt; collate&lt;charT> >(*this).compare<wbr/>
      (s1.data(), s1.data()+s1.size(), s2.data(), s2.data()+s2.size()) &lt; 0;</code></p>
    </div>


    <h4>Modify [conversions.string]</h4>
<pre><code>namespace std {
template&lt;class Codecvt, class Elem = wchar_t,
    class Wide_alloc = std::allocator&lt;Elem>,
    class Byte_alloc = std::allocator&lt;char> > class wstring_convert {
    // ...
    <ins>wide_string from_bytes(const basic_string_ref&lt;char>& str);
    byte_string to_bytes(const basic_string_ref&lt;Elem>& wstr);</ins>
    // ...
  };
}</code></pre>

<pre><code>wide_string from_bytes(char byte);
wide_string from_bytes(const char *ptr);
wide_string from_bytes(const byte_string& str);
<ins>wide_string from_bytes(const basic_string_ref&lt;char>& str);</ins>
wide_string from_bytes(const char *first, const char *last);</code></pre>

     <p class="attribute"><i>Effects</i>: The first member function shall
     convert the single-element sequence byte to a wide string.  The second
     member function shall convert the null-terminated sequence beginning at ptr
     to a wide string. The third <del>member function </del><ins>and fourth
     member functions </ins>shall convert the sequence stored in str to a wide
     string. The <del>fourth </del><ins>fifth </ins>member function shall
     convert the sequence defined by the range [first,last) to a wide
     string.</p>

<pre><code>byte_string to_bytes(Elem wchar);
byte_string to_bytes(const Elem *wptr);
byte_string to_bytes(const wide_string& wstr);
<ins>byte_string to_bytes(const basic_string_ref&lt;Elem>& wstr);</ins>
byte_string to_bytes(const Elem *first, const Elem *last);</code></pre>

    <p class="attribute"><i>Effects</i>: The first member function shall convert
    the single-element sequence wchar to a byte string.  The second member
    function shall convert the null-terminated sequence beginning at wptr to a
    byte string. The third <del>member function </del><ins>and fourth member
    functions </ins>shall convert the sequence stored in wstr to a byte
    string. The <del>fourth </del><ins>fifth </ins>member function shall convert
    the sequence defined by the range [first,last) to a byte string.</p>


    <h3 id="re">Clause 28, Regular expressions library</h3>

    <h4>Add to the appropriate places within [re.syn]</h4>
<pre><code>template &lt;class BiIter, class ST>
  bool operator==(
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
    const sub_match&lt;BiIter>& rhs);
template &lt;class BiIter, class ST>
  bool operator!=(
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
    const sub_match&lt;BiIter>& rhs);
template &lt;class BiIter, class ST>
  bool operator&lt;(
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
    const sub_match&lt;BiIter>& rhs);
template &lt;class BiIter, class ST>
  bool operator>(
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
    const sub_match&lt;BiIter>& rhs);
template &lt;class BiIter, class ST>
  bool operator>=(
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
    const sub_match&lt;BiIter>& rhs);
template &lt;class BiIter, class ST>
  bool operator&lt;=(
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
    const sub_match&lt;BiIter>& rhs);

template &lt;class BiIter, class ST>
  bool operator==(
    const sub_match&lt;BiIter>& lhs,
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> rhs);
template &lt;class BiIter, class ST>
bool operator!=(
       const sub_match&lt;BiIter>& lhs,
        basic_string_ref&lt;
          typename iterator_traits&lt;BiIter>::value_type, ST> rhs);
template &lt;class BiIter, class ST>
  bool operator&lt;(
    const sub_match&lt;BiIter>& lhs,
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> rhs);
template &lt;class BiIter, class ST>
  bool operator>(
    const sub_match&lt;BiIter>& lhs,
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> rhs);
template &lt;class BiIter, class ST>
  bool operator>=(
    const sub_match&lt;BiIter>& lhs,
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> rhs);
template &lt;class BiIter, class ST>
  bool operator&lt;=(
    const sub_match&lt;BiIter>& lhs,
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> rhs);

template &lt;class ST, class Allocator, class charT, class traits>
  bool regex_match(basic_string_ref&lt;charT, ST> s,
                   match_results&lt;
                     typename basic_string_ref&lt;charT, ST>::const_iterator,
                     Allocator>& m,
                   const basic_regex&lt;charT, traits>& e,
                   regex_constants::match_flag_type flags =
                     regex_constants::match_default);
template &lt;class ST, class charT, class traits>
  bool regex_match(basic_string_ref&lt;charT, ST> s,
                   const basic_regex&lt;charT, traits>& e,
                   regex_constants::match_flag_type flags =
                     regex_constants::match_default);

template &lt;class ST, class charT, class traits>
  bool regex_search(basic_string_ref&lt;charT, ST> s,
                    const basic_regex&lt;charT, traits>& e,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
template &lt;class ST, class Allocator, class charT, class traits>
  bool regex_search(basic_string_ref&lt;charT, ST> s,
                    match_results&lt;
                      typename basic_string_ref&lt;charT, ST>::const_iterator,
                      Allocator>& m,
                    const basic_regex&lt;charT, traits>& e,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);

template &lt;class OutputIterator, class BidirectionalIterator,
    class traits, class charT, class ST>
  OutputIterator
  regex_replace(OutputIterator out,
                BidirectionalIterator first, BidirectionalIterator last,
                const basic_regex&lt;charT, traits>& e,
                basic_string_ref&lt;charT, ST> fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);</code></pre>
    <div class="ednote"><p>This wording <a href="#no-fix-2216">does not include
    a fix</a> for <a
    href="http://cplusplus.github.com/LWG/lwg-active.html#2216">LWG issue
    2216</a>. That is, the new overloads always use the default
    allocator.</p></div>
<pre><code>template &lt;class traits, class charT, class ST, class FST>
  basic_string&lt;charT, ST>
  regex_replace(basic_string_ref&lt;charT, ST> s,
                const basic_regex&lt;charT, traits>& e,
                basic_string_ref&lt;charT, FST> fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
template &lt;class traits, class charT, class ST>
  basic_string&lt;charT, ST>
  regex_replace(basic_string_ref&lt;charT, ST> s,
                const basic_regex&lt;charT, traits>& e,
                const charT* fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
template &lt;class traits, class charT, class ST>
  basic_string&lt;charT>
  regex_replace(const charT* s,
                const basic_regex&lt;charT, traits>& e,
                basic_string_ref&lt;charT, ST> fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
template &lt;class traits, class charT, class ST, class SA,
          class FST>
  basic_string&lt;charT, ST, SA>
  regex_replace(const basic_string&lt;charT, ST, SA>& s,
                const basic_regex&lt;charT, traits>& e,
                basic_string_ref&lt;charT, FST> fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
template &lt;class traits, class charT, class ST,
          class FST, class FSA>
  basic_string&lt;charT, ST>
  regex_replace(basic_string_ref&lt;charT, ST> s,
                const basic_regex&lt;charT, traits>& e,
                const basic_string&lt;charT, FST, FSA>& fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);</code></pre>


    <h4>Add to the appropriate places within [re.regex]</h4>
<pre><code>template &lt;class ST>
  explicit basic_regex(basic_string_ref&lt;charT, ST> p,
                       flag_type f = regex_constants::ECMAScript);
template &lt;class ST>
  basic_regex& operator=(basic_string_ref&lt;charT, ST> p);
template &lt;class string_traits>
  basic_regex& assign(basic_string_ref&lt;charT, string_traits> s,
                      flag_type f = regex_constants::ECMAScript);</code></pre>


    <h4>Modify [re.regex.construct]</h4>
<pre><code><ins>template &lt;class ST>
  basic_regex(basic_string_ref&lt;charT, ST> s,
              flag_type f = regex_constants::ECMAScript);</ins>
template &lt;class ST, class SA>
basic_regex(const basic_string&lt;charT, ST, SA>& s,
            flag_type f = regex_constants::ECMAScript);</code></pre>
    <div class="attributes">
      <p><i>Throws</i>: regex_error if s is not a valid regular expression.</p>
      <p><i>Effects</i>: Constructs an object of class basic_regex; the object’s internal finite state machine is con- structed from the regular expression contained in the string s, and interpreted according to the flags specified in f.</p>
      <p><i>Postconditions</i>: flags() returns f. mark_count() returns the number of marked sub-expressions within the expression.</p>
    </div>


    <h4>Modify [re.regex.assign]</h4>
<pre><code><ins>template &lt;class ST>
  basic_regex& operator=(basic_string_ref&lt;charT, ST> p);</ins>
template &lt;class ST, class SA>
  basic_regex& operator=(const basic_string&lt;charT, ST, SA>& p);</code></pre>
    <p class="attribute"><i>Effects</i>: returns assign(p).</p>

<pre><code><ins>template &lt;class string_traits>
  basic_regex& assign(basic_string_ref&lt;charT, string_traits> s,
                      flag_type f = regex_constants::ECMAScript);</ins>
template &lt;class string_traits, class A>
  basic_regex& assign(const basic_string&lt;charT, string_traits, A>& s,
                      flag_type f = regex_constants::ECMAScript);</code></pre>
    <div class="attributes">
      <p><i>Throws</i>: regex_error if s is not a valid regular expression.</p>
      <p><i>Returns</i>: *this.</p>
      <p><i>Effects</i>: Assigns the regular expression contained in the string s, interpreted according the flags specified in f. If an exception is thrown, *this is unchanged.</p>
      <p><i>Postconditions</i>: If no exception is thrown, flags() returns f and mark_count() returns the number of marked sub-expressions within the expression.</p>
    </div>


    <h4>Add to [re.submatch]</h4>
    <pre><code>int compare(basic_string_ref&lt;value_type> s) const;</code></pre>


    <h4>Add to [re.submatch.members]</h4>
    <pre><code>int compare(basic_string_ref&lt;value_type> s) const;</code></pre>
    <p class="attribute"><i>Returns</i>: str().compare(s).</p>


    <h4>Add to [re.submatch.op]</h4>

<pre><code>template &lt;class BiIter, class ST>
  bool operator==(
    basic_string_ref&lt;
      typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
    const sub_match&lt;BiIter>& rhs);</code></pre>
    <p class="attributes"><i>Returns</i>: rhs.compare(basic_string_ref&lt;typename iterator_traits&lt;BiIter>::value_type>(lhs.data(), lhs.size())) == 0.</p>
    <p>[ Footnote: This and the other comparison operators ignore the basic_string_ref's traits. -- end footnote]</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator!=(
basic_string_ref&lt;
  typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
const sub_match&lt;BiIter>& rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: !(lhs == rhs).</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator&lt;(
basic_string_ref&lt;
  typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
const sub_match&lt;BiIter>& rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: rhs.compare(basic_string_ref&lt;typename iterator_traits&lt;BiIter>::value_type>(lhs.data(), lhs.size())) > 0.</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator>(
basic_string_ref&lt;
  typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
const sub_match&lt;BiIter>& rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: rhs &lt; lhs.</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator>=(
basic_string_ref&lt;
  typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
const sub_match&lt;BiIter>& rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: !(lhs &lt; rhs).</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator&lt;=(
basic_string_ref&lt;
  typename iterator_traits&lt;BiIter>::value_type, ST> lhs,
const sub_match&lt;BiIter>& rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: !(rhs &lt; lhs).</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator==(const sub_match&lt;BiIter>& lhs,
             basic_string_ref&lt;
               typename iterator_traits&lt;BiIter>::value_type, ST> rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: lhs.compare(basic_string_ref&lt;typename iterator_traits&lt;BiIter>::value_type>(rhs.data(), rhs.size())) == 0.</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator!=(const sub_match&lt;BiIter>& lhs,
                  basic_string_ref&lt;
                    typename iterator_traits&lt;BiIter>::value_type, ST> rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: !(lhs == rhs).</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator&lt;(const sub_match&lt;BiIter>& lhs,
            basic_string_ref&lt;
              typename iterator_traits&lt;BiIter>::value_type, ST> rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: lhs.compare(basic_string_ref&lt;typename iterator_traits&lt;BiIter>::value_type>(rhs.data(), rhs.size())) &lt; 0.</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator>(const sub_match&lt;BiIter>& lhs,
            basic_string_ref&lt;
              typename iterator_traits&lt;BiIter>::value_type, ST> rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: rhs &lt; lhs.</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator>=(const sub_match&lt;BiIter>& lhs,
             basic_string_ref&lt;
               typename iterator_traits&lt;BiIter>::value_type, ST> rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: !(lhs &lt; rhs).</p>

<pre><code>template &lt;class BiIter, class ST>
  bool operator&lt;=(const sub_match&lt;BiIter>& lhs,
             basic_string_ref&lt;
               typename iterator_traits&lt;BiIter>::value_type, ST> rhs);</code></pre>
    <p class="attribute"><i>Returns</i>: !(rhs &lt; lhs).</p>


    <h4>Add to the appropriate places within [re.results]</h4>
<pre><code>template &lt;class OutputIter, class ST>
       OutputIter
       format(OutputIter out,
              basic_string_ref&lt;char_type, ST> fmt,
              regex_constants::match_flag_type flags =
                regex_constants::format_default) const;
template &lt;class ST>
      basic_string&lt;char_type, ST>
      format(basic_string_ref&lt;char_type, ST> fmt,
             regex_constants::match_flag_type flags =
               regex_constants::format_default) const;</code></pre>


    <h4>Modify [re.results.form]</h4>
<pre><code><ins>template &lt;class OutputIter, class ST>
  OutputIter format(OutputIter out,
                    basic_string_ref&lt;char_type, ST> fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::format_default) const;</ins>
template &lt;class OutputIter, class ST, class SA>
  OutputIter format(OutputIter out,
                    const basic_string&lt;char_type, ST, SA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::format_default) const;</code></pre>
    <p class="attribute"><i>Effects</i>: Equivalent to <code>return format(<wbr/>out,<wbr/> fmt.data(),<wbr/> fmt.data() + fmt.size(),<wbr/> flags)</code>.</p>

<pre><code><ins>template &lt;class ST>
  basic_string&lt;char_type, ST>
  format(basic_string_ref&lt;char_type, ST>& fmt,
    regex_constants::match_flag_type flags =
      regex_constants::format_default) const;</ins></code></pre>
    <div class="attributes">
      <p><ins><i>Requires</i>: <code>ready() == true</code>.</ins></p>
      <p><ins><i>Effects</i>: Constructs an empty string <code>result</code> of
      type <code>basic_string&lt;char_type, ST></code> and calls
      <code>format(back_inserter(result), fmt, flags)</code>.</ins></p>
      <p><ins><i>Returns</i>: <code>result</code>.</ins></p>
    </div>


    <h4>Modify [re.alg.match]</h4>
<pre><code><ins>template &lt;class ST, class Allocator, class charT, class traits>
  bool regex_match(basic_string_ref&lt;charT, ST> s,
                   match_results&lt;
                     typename basic_string_ref&lt;charT, ST>::const_iterator,
                     Allocator>& m,
                   const basic_regex&lt;charT, traits>& e,
                   regex_constants::match_flag_type flags =
                     regex_constants::match_default);</ins>
template &lt;class ST, class SA, class Allocator, class charT, class traits>
  bool regex_match(const basic_string&lt;charT, ST, SA>& s,
                   match_results&lt;
                     typename basic_string&lt;charT, ST, SA>::const_iterator,
                     Allocator>& m,
                   const basic_regex&lt;charT, traits>& e,
                   regex_constants::match_flag_type flags =
                     regex_constants::match_default);</code></pre>
    <p class="attribute"><i>Returns</i>: regex_match(s.begin(), s.end(), m, e, flags).</p>


<pre><code><ins>template &lt;class ST, class charT, class traits>
  bool regex_match(basic_string_ref&lt;charT, ST> s,
                   const basic_regex&lt;charT, traits>& e,
                   regex_constants::match_flag_type flags =
                     regex_constants::match_default);</ins>
template &lt;class ST, class SA, class charT, class traits>
  bool regex_match(const basic_string&lt;charT, ST, SA>& s,
                   const basic_regex&lt;charT, traits>& e,
                   regex_constants::match_flag_type flags =
                     regex_constants::match_default);</code></pre>

    <p class="attribute"><i>Returns</i>: regex_match(s.begin(), s.end(), e, flags).</p>

    <h4>Modify [re.alg.search]</h4>
<pre><code><ins>template &lt;class ST, class Allocator, class charT, class traits>
  bool regex_search(basic_string_ref&lt;charT, ST> s,
                    match_results&lt;
                      typename basic_string_ref&lt;charT, ST>::const_iterator,
                      Allocator>& m,
                    const basic_regex&lt;charT, traits>& e,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);</ins>
template &lt;class ST, class SA, class Allocator, class charT, class traits>
  bool regex_search(const basic_string&lt;charT, ST, SA>& s,
                    match_results&lt;
                      typename basic_string&lt;charT, ST, SA>::const_iterator,
                      Allocator>& m,
                    const basic_regex&lt;charT, traits>& e,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);</code></pre>
    <p class="attribute"><i>Returns</i>: The result of <code>regex_search(s.begin(), s.end(), m, e, flags)</code>.</p>

<pre><code><ins>template &lt;class ST, class SA, class charT, class traits>
  bool regex_search(basic_string_ref&lt;charT, ST>& s,
                    const basic_regex&lt;charT, traits>& e,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);</ins>
template &lt;class ST, class SA, class charT, class traits>
  bool regex_search(const basic_string&lt;charT, ST, SA>& s,
                    const basic_regex&lt;charT, traits>& e,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);</code></pre>
    <p class="attribute"><i>Returns</i>: <code>regex_search(s.begin(), s.end(), e, flags)</code>.</p>

    <h4>Modify [re.alg.replace]</h4>
<pre><code>template &lt;class OutputIterator, class BidirectionalIterator,
    class traits, class charT, class ST, class SA>
  OutputIterator
  regex_replace(OutputIterator out,
                BidirectionalIterator first, BidirectionalIterator last,
                const basic_regex&lt;charT, traits>& e,
                const basic_string&lt;charT, ST, SA>& fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
<ins>template &lt;class OutputIterator, class BidirectionalIterator,
    class traits, class charT, class ST>
  OutputIterator
  regex_replace(OutputIterator out,
                BidirectionalIterator first, BidirectionalIterator last,
                const basic_regex&lt;charT, traits>& e,
                basic_string_ref&lt;charT, ST> fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);</ins>
template &lt;class OutputIterator, class BidirectionalIterator,
    class traits, class charT>
  OutputIterator
  regex_replace(OutputIterator out,
                BidirectionalIterator first, BidirectionalIterator last,
                const basic_regex&lt;charT, traits>& e,
                const charT* fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Constructs a regex_iterator object i as if by regex_iterator&lt;BidirectionalIterator, charT, traits> i(first, last, e, flags), and uses i to enumerate through all of the matches m of type match_results&lt;BidirectionalIterator> that occur within the sequence [first,last ). If no such matches are found and !(flags & regex_constants ::format_no_copy) then calls std::copy(first, last, out). If any matches are found then, for each such match, if !(flags & regex_constants::format_no_copy), calls std::copy(m.prefix().first, m.prefix().second, out), and then calls m.format(out, fmt, flags) for the first <del>form </del><ins>and second forms </ins>of the function and m.format(out, fmt, fmt + char_traits&lt;charT>::length(fmt), flags) for the <del> second</del><ins> third</ins>. Finally, if such a match is found and !(flags & regex_constants ::format_no_copy), calls std:: copy(last_m.suffix().first, last_m.suffix().second, out) where last_m is a copy of the last match found. If flags & regex_constants::format_first_only is non-zero then only the first match found is replaced.</p>
      <p><i>Returns</i>: out.</p>
    </div>

<pre><code><ins>template &lt;class traits, class charT, class ST, class FST, class FSA>
  basic_string&lt;charT, ST>
  regex_replace(basic_string_ref&lt;charT, ST> s,
                const basic_regex&lt;charT, traits>& e,
                const basic_string&lt;charT, FST, FSA>& fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
template &lt;class traits, class charT, class ST, class FST>
  basic_string&lt;charT, ST>
  regex_replace(basic_string_ref&lt;charT, ST> s,
                const basic_regex&lt;charT, traits>& e,
                basic_string_ref&lt;charT, FST> fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
template &lt;class traits, class charT, class ST>
  basic_string&lt;charT, ST>
  regex_replace(basic_string_ref&lt;charT, ST> s,
  const basic_regex&lt;charT, traits>& e,
                const charT* fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);</ins></code></pre>
    <div class="attributes">
      <p><ins><i>Effects</i>: Constructs an empty string result of type basic_string&lt;charT, ST> and calls regex_replace(back_inserter(result), s.begin(), s.end(), e, fmt, flags).</ins></p>
      <p><ins><i>Returns</i>: result.</ins></p>
    </div>

<pre><code>template &lt;class traits, class charT, class ST, class SA, class FST, class FSA>
  basic_string&lt;charT, ST, SA>
  regex_replace(const basic_string&lt;charT, ST, SA>& s,
                const basic_regex&lt;charT, traits>& e,
                const basic_string&lt;charT, FST, FSA>& fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
<ins>template &lt;class traits, class charT, class ST, class SA, class FST>
  basic_string&lt;charT, ST, SA>
  regex_replace(const basic_string&lt;charT, ST, SA>& s,
                const basic_regex&lt;charT, traits>& e,
                basic_string_ref&lt;charT, FST> fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);</ins>
template &lt;class traits, class charT, class ST, class SA>
basic_string&lt;charT, ST, SA>
regex_replace(const basic_string&lt;charT, ST, SA>& s,
              const basic_regex&lt;charT, traits>& e,
              const charT* fmt,
              regex_constants::match_flag_type flags =
                regex_constants::match_default);</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Constructs an empty string result of type basic_string&lt;charT, ST, SA> and calls regex_replace(back_inserter(result), s.begin(), s.end(), e, fmt, flags).</p>
      <p><i>Returns</i>: result.</p>
    </div>

<pre><code>template &lt;class traits, class charT, class ST, class SA>
  basic_string&lt;charT>
  regex_replace(const charT* s,
                const basic_regex&lt;charT, traits>& e,
                const basic_string&lt;charT, ST, SA>& fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);
<ins>template &lt;class traits, class charT, class ST>
  basic_string&lt;charT>
  regex_replace(const charT* s,
                const basic_regex&lt;charT, traits>& e,
                basic_string_ref&lt;charT, ST> fmt,
                   regex_constants::match_flag_type flags =
                     regex_constants::match_default);</ins>
template &lt;class traits, class charT>
  basic_string&lt;charT>
  regex_replace(const charT* s,
                const basic_regex&lt;charT, traits>& e,
                const charT* fmt,
                regex_constants::match_flag_type flags =
                  regex_constants::match_default);</code></pre>
    <div class="attributes">
      <p><i>Effects</i>: Constructs an empty string result of type basic_string&lt;charT> and calls regex_replace( back_inserter(result), s, s + char_traits&lt;charT>::length(s), e, fmt, flags).</p>
      <p><i>Returns</i>: result.</p>
    </div>
  </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, Daniel Krügler,
    and Alisdair Meredith for help, advice, and wording in this paper.</p>
  </section>
</body>
</html>
