<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="generator" content="dascandy/fiets">
<title>
std::zstring_view</title>
  <style type="text/css">
body {
  margin: 5em;
  font-family: sans-serif;
  hyphens: auto;
  line-height: 1.35;
}
ul {
  padding-left: 2em;
}
h1, h2, h3, h4 {
  position: relative;
  line-height: 1;
}
h1.title {
}
h2.subtitle {
}
h1.toc a, h2.toc a, h3.toc a, h4.toc a {
  text-decoration: none;
  color: #000000;
}
h1.toc a:hover, h2.toc a:hover, h3.toc a:hover, h4.toc a:hover {
  text-decoration: underline;
}
a.self-link {
  position: absolute;
  top: 0;
  left: calc(-1 * (3.5rem - 26px));
  width: calc(3.5rem - 26px);
  height: 2em;
  text-align: center;
  border: none;
  transition: opacity .2s;
  opacity: .5;
  font-family: sans-serif;
  font-weight: normal;
  font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
span.identifier {
  font-style: italic;
}
span.special {
  color: #bf003f;
}
span.keyword {
  color: #0030cf;
}
span.comment {
  color: #00c000;
}
span.new {
  text-decoration: underline;
  background-color: #00ff40;
}
div.code, span.code {
  font-family: Courier New, monospace;
  background-color: #e8e8e8;
  white-space: pre;
}
span.delete {
  text-decoration: line-through;
  background-color: #bf0303;
}
p.indent {
  margin-left: 50px;
}
p.quote {
  margin-left: 50px;
  border: 2px solid black;
  background-color: #f0f0e0;
}
table {
  border: 1px solid black;
  border-collapse: collapse;
  margin-left: auto;
  margin-right: auto;
  margin-top: 0.8em;
  text-align: left;
  hyphens: none; 
}
td, th {
  padding-left: 1em;
  padding-right: 1em;
  vertical-align: top;
}
th {
  border-bottom: 2px solid black;
  background-color: #f0f0f0;
}
</style>
</head>
<body>
<h1 class="title" style="text-align:center">std::zstring_view</h1><table><tbody><tr><td> Document # </td><td> P3655R2 </td></tr><tr><td> Date </td><td> 2025-06-15 </td></tr><tr><td> Targeted subgroups </td><td> LEWG </td></tr><tr><td> Ship vehicle </td><td> C++29 </td></tr><tr><td> Reply-to </td><td> Peter Bindels &lt;dascandy@gmail.com&gt; </td></tr><tr><td> </td><td> Hana Dusíková &lt;hanicka@hanicka.net&gt; </td></tr><tr><td> </td><td> Jeremy Rifkin &lt;jeremy@rifkin.dev&gt; </td></tr><tr><td> </td><td> Marco Foco &lt;marco.foco@gmail.com&gt; </td></tr><tr><td> </td><td> Alexey Shevlyakov &lt;aleshevl@gmail.com&gt; </td></tr></tbody></table><h1 data-number="1" id="Abstract"><span class="header-section-number">1</span> Abstract<a href="#Abstract" class="self-link"></a></h1><p>We propose a standard string view type that guarantees null-termination.</p><h1 data-number="2" id="Introduction"><span class="header-section-number">2</span> Introduction<a href="#Introduction" class="self-link"></a></h1><p>C++17 introduced <span class="code">std<span class="special">::</span>string_view</span>, a non-owning view of a continuous sequence of characters. It is cheap to use, offers fast operations, and replaced most uses of <span class="code"><span class="keyword">const</span> std<span class="special">::</span>string<span class="special">&amp;</span></span> or <span class="code"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span></span> as function parameters.  The utility and interface of string views as well as the benefits of not having to do unnecessary <span class="code">strlen</span> calculations on C-style strings makes string view types highly desirable for working with strings in C++.</p><p>Unlike <span class="code"><span class="keyword">const</span> std<span class="special">::</span>string<span class="special">&amp;</span></span> and many but not all <span class="code"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span></span>, <span class="code">std<span class="special">::</span>string_view</span> is not null-terminated. This allows it to have fast and cheap substring operations. However, this also means <span class="code">std<span class="special">::</span>string_view</span> is not a suitable replacement for either of the two aforementioned types whenever a null-terminated C-style string is needed. While most C++ code mostly interfaces with C++ code, it is not uncommon to need to use operating system calls, C interfaces, third-party library APIs, or even C++ standard library APIs which require null-terminated strings. Because of a lack of a desirable option for passing non-owned null-terminated strings, <span class="code">std<span class="special">::</span>string_view</span> parameters are none the less sometimes used today in cases where null-terminated strings are needed, calling <span class="code">std<span class="special">::</span>string_view<span class="special">::</span>data</span> to get a <span class="code"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span></span>. This is, needless to say, very bug-prone.</p><p>For this reason, many C++ developers use custom <span class="code">zstring_view</span> or <span class="code">cstring_view</span> types which are guaranteed to be null-terminated. We propose standardizing this utility.</p><h1 data-number="3" id="Previous-Papers"><span class="header-section-number">3</span> Previous Papers<a href="#Previous-Papers" class="self-link"></a></h1><p>The idea of <span class="code">zstring_view</span> was present even in the original paper for <span class="code">string_view</span> (Sept 2012 - Feb 2014) <a href="N3921">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3921.html#null-termination</a>:</p><p class="quote">Another option would be to define a separate zstring_view class to represent null-terminated strings and let it decay to string_view when necessary. That's plausible but not part of this proposal.</p><p>An attempt was made in Feb 2019 to concretely propose the type (renamed to <span class="code">cstring_view</span>) with <a href="P1402">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1402r0.pdf</a>, but it failed to gain consensus in LEWGI at <a href="Kona">https://wiki.edg.com/bin/view/Wg21kona2019/P1402</a>. In fact, the discussion there concluded with "CONSENSUS: We will not pursue P1402R0 or this problem space." It is also worth noting that contracts were briefly contemplated in the minutes as a way of addressing the problem, however, contracts can't check for a null character safely as it wouldn't be part of the view. Similarly, other runtime checks for <span class="code">string_view</span> null-termination are off the table.</p><p>However, in 2024 <a href="P3081 Core safety profiles for C++26">https://wg21.link/p3081</a> was published which contains an aside regarding a null-terminated <span class="code">zstring_view</span> in section 8, noting:</p><p class="quote">This is one of the commonly-requested features from the <a href="GSL">https://github.com/microsoft/GSL</a> library that does not yet have a std:: equivalent. It was specifically requested by several reviewers of this work.</p><p>During the discussion, it was made clear that <span class="code">zstring_view</span> deserves attention on its own and it should not be happenstance introduced as part of an entirely different topic. While P3081 did not end up passing for reasons other than <span class="code">zstring_view</span>, it is another example of the utility being seen as desirable.</p><p>We also have <a href="P2996 Reflection for C++26">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2996r9.html</a>, which in its specification of functions returning a <span class="code">string_view</span> or <span class="code">u8string_view</span> tries its best to say it's actually supposed to be a <span class="code">zstring_view</span>, except without naming the type for existential reasons:</p><p class="quote">Any function in namespace std::meta that whose return type is string_view or u8string_view returns an object V such that <span class="code">V<span class="special">.</span>data<span class="special">()[</span>V<span class="special">.</span>size<span class="special">()]</span> <span class="special">==</span> <span class="special">'\</span>0<span class="special">'</span></span>.</p><p>As such, we do believe that there is both space for such a type, and a desire from multiple angles to have it defined in the standard library.</p><h1 data-number="4" id="Reasons-to-have-the-type"><span class="header-section-number">4</span> Reasons to have the type<a href="#Reasons-to-have-the-type" class="self-link"></a></h1><p>Many functions right now whether C++ standard library calls, operating system calls, or third-party library calls require null-terminated C-style strings. Absent an efficient type that can represent a non-owning view of a null-terminated string, these functions must take either a <span class="code"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span></span> and incur potential <span class="code">strlen</span> overhead, take a <span class="code"><span class="keyword">const</span> std<span class="special">::</span>string<span class="special">&amp;</span></span> and possibly superfluously copy and allocate, take a <span class="code">string_view</span> and make a copy, or haphazardly take a <span class="code">std<span class="special">::</span>string_view</span> with a fragile unenforceable contract that it is a view of a null-terminated string. Such a contract would be unenforceable because <span class="code"><span class="keyword">pre</span><span class="special">(</span>sv<span class="special">[</span>sv<span class="special">.</span>size<span class="special">()]</span> <span class="special">==</span> 0<span class="special">)</span></span> is potentially undefined behavior.</p><p>String views tend to start their life coming from a string literal or from a type that owns its internal buffer, often <span class="code">std<span class="special">::</span>string</span>. Both of these are places that can always create a <span class="code">zstring_view</span> instead, as they both know their data is inherently null terminated.</p><p>Strings are very often just passed along with a non-owning string type all the way to where they are used as data. Some of these potential uses, such as calling <span class="code">std<span class="special">::</span>ofstream<span class="special">::</span>write</span>, do not rely on the null terminator, but others, like <span class="code">std<span class="special">::</span>ofstream<span class="special">::</span>ofstream</span>, do. Using <span class="code">string_view</span> as the intermediate type loses the knowledge that a null terminator is already guaranteed to be present, requiring the developer to either make assumptions or make a copy. Another common use might be creating a stringstream from a string <a href="StackOverflow question">https://stackoverflow.com/questions/58524805/is-there-a-way-to-create-a-stringstream-from-a-string-view-without-copying-data</a>.</p><p>We do not have to look far for examples of <span class="code">std<span class="special">::</span>string_view</span> being used in bug-prone ways with APIs expecting null-terminators. Searching <span class="code"><span class="special">/\.</span>data<span class="special">\(\)/</span> string_view language<span class="special">:</span>c<span class="special">++</span> <span class="special">-</span>is<span class="special">:</span>fork</span> on GitHub code search turns up two examples on the first page:</p><p>From <a href="surge-synthesizer/shortcircuit-xt">https://github.com/surge-synthesizer/shortcircuit-xt/blob/ba6ea3a2e703e4fa0ed069427aa42b668699b624/libs/md5sum/demo.cc#L37</a></p><code><div class="code">std<span class="special">::</span>optional<span class="special">&lt;</span>std<span class="special">::</span>string<span class="special">&gt;</span> hash_file<span class="special">(</span><span class="keyword">const</span> std<span class="special">::</span>string_view <span class="special">&amp;</span>file_name<span class="special">)</span> <span class="special">{</span>
    <span class="keyword">auto</span> fd <span class="special">=</span> open<span class="special">(</span>file_name<span class="special">.</span>data<span class="special">(),</span> O_RDONLY<span class="special">);</span>
    <span class="special">...</span></div></code><p>From <a href="VisualGMQ/gmq_header">https://github.com/VisualGMQ/gmq_header/blob/cbc2853f391acc51ddd25a50d567cac404776413/log.hpp#L66</a></p><code><div class="code"><span class="keyword">void</span> log<span class="special">(</span>Level level<span class="special">,</span> std<span class="special">::</span>string_view funcName<span class="special">,</span> std<span class="special">::</span>string_view filename<span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> line<span class="special">,</span> Args<span class="special">&amp;&amp;</span><span class="special">...</span> args<span class="special">)</span> <span class="special">{</span>
    <span class="keyword">if</span> <span class="special">(</span>level <span class="special">&lt;</span><span class="special">=</span> level_<span class="special">)</span> <span class="special">{</span>
        printf<span class="special">("[%</span>s<span class="special">][%</span>s<span class="special">][%</span>s<span class="special">][%</span>u<span class="special">]",</span> Level2Str<span class="special">(</span>level<span class="special">).</span>data<span class="special">(),</span> filename<span class="special">.</span>data<span class="special">(),</span> funcName<span class="special">.</span>data<span class="special">(),</span> line<span class="special">);</span>
        <span class="special">...</span></div></code><p>These two examples could be argued to be bad code or misuses of <span class="code">std<span class="special">::</span>string_view</span>, however, the fact that they are written reflects the desire for the ability to use string view types in such cases.</p><p>These problems are visible enough that we have targeted patches for specific instances of this problem in the standard - <a href="P2495">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2495r0.pdf</a> attempts to directly patch this specific example. The solution bypasses that the problem is that we're missing an unbroken type-safe chain of knowledge that the value being passed is or is not null-terminated.</p><p>The type effectively fills out the design space that exists around strings within C++. We started off with <span class="code">std<span class="special">::</span>string</span> as an owning string type, ambiguously being specified as having a null terminator or not, clarified in C++11 to definitely *have* a null terminator. C++14 added <span class="code">std<span class="special">::</span>string_view</span> to that set, offering a non-null-terminated non-owning string type. The type itself raises the question, should we add a non-null-terminated owning string type, and/or a null-terminated non-owning string type? We're proposing the last of these, leaving only the non-null-terminated owning string type as not present. We believe there is no situation to be written where a non-null-terminated owning string type would have a measurable benefit over the null-terminated owning string type that we have, and as such it is not worth the added complexity.</p><p>Without them we retain the question we had before - <span class="code"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span></span>, <span class="code"><span class="keyword">const</span> std<span class="special">::</span>string<span class="special">&amp;</span></span> or <span class="code">string_view</span>? The first loses lots of type safety and potentially requires redundant <span class="code">strlen</span> computation elsewhere in the software, the second requires it to be a <span class="code">std<span class="special">::</span>string</span> but retains null-termination knowledge, the last offers the ability to send any string type constructible to a string_view, but loses any knowledge of null termination. For the common case of passing along "some string input" to a function that ends up requiring null termination, the proposed <span class="code">zstring_view</span> is the only type that properly captures it.</p><p>Since the first draft of this paper the use of <span class="code">cstring_view</span> and <span class="code">zstring_view</span> on Github has grown from 1.9k to 2.1k, indicating active use, and in many cases people adding new implementations of the type. Many contain the subtle bugs that we highlight in this paper, illustrating why it is a good idea to add the type to the standard.</p><h1 data-number="5" id="Reasons-not-to-have-the-type"><span class="header-section-number">5</span> Reasons not to have the type<a href="#Reasons-not-to-have-the-type" class="self-link"></a></h1><p>In an ideal world, we could actually fix the operating systems and third-party libraries to accept pointer-and-size strings in all places, removing the need for null termination to exist, and for null termination propagation to be relevant. Sometimes, in particular from environments where this may not be unrealistic in a subset, the argument is voiced that <span class="code">zstring_view</span> does not offer any benefits.</p><p>Adding the type complicates the type system around strings by having more options for string types. This is not as much of an argument as it seems, since for each site a single type is the most appropriate, and the only places that would differ are those where the difference can make a meaningful performance impact - ie, the exact kind of tight loop where the type is useful for being able to make the difference.</p><h1 data-number="6" id="Subtle-details"><span class="header-section-number">6</span> Subtle details<a href="#Subtle-details" class="self-link"></a></h1><h2 data-number="6.1" id="zstring_view-and-string_view-relation"><span class="header-section-number">6.1</span> zstring_view and string_view relation<a href="#zstring_view-and-string_view-relation" class="self-link"></a></h2><p>Initially we expected that <span class="code">zstring_view</span> may be implementable in terms of <span class="code">string_view</span>. This is not actually true; in particular it is not well-formed to use <span class="code">string_view</span>'s <span class="code"><span class="keyword">operator</span><span class="special">=</span></span> to assign a non-null-terminated <span class="code">string_view</span> to a <span class="code">zstring_view</span>. As such, there can not be an inheritance relation between the two.</p><p><span class="code">zstring_view</span> is transparently convertible to a <span class="code">string_view</span>. For the conversion operator, there is no <span class="code"><span class="keyword">operator</span><span class="special">=</span></span> that could affect the original <span class="code">zstring_view</span>, and as such it is a correct change to do. It in particular makes it so that any use of <span class="code">zstring_view</span> in places where string_view is expected or desired will work without additional work.</p><p>This brings into reality an overload ambiguity:</p><code><div class="code">  <span class="keyword">void</span> handle<span class="special">(</span>string_view v<span class="special">);</span>
  <span class="keyword">void</span> handle<span class="special">(</span>zstring_view v<span class="special">);</span>
  handle<span class="special">("</span>Hello World<span class="special">!");</span></div></code><p>This is now an ambiguous function call. It is not a new problem; <a href="Example on Godbolt">https://godbolt.org/z/c31e31fKW</a> shows that the exact same problem already happens with regular <span class="code">std<span class="special">::</span>string</span> and <span class="code">std<span class="special">::</span>string_view</span>. The reason is somewhat fundamental; all three types model the concept "string" and *are* ambiguous. The user should be clear about which properties of string it's expecting. Adding this new type only adds to the vocabulary the option to say "non-owning null-terminated", giving the user better choices rather than complicating it.</p><h3 data-number="6.1.1" id="Deprioritizing-one-overload"><span class="header-section-number">6.1.1</span> Deprioritizing one overload<a href="#Deprioritizing-one-overload" class="self-link"></a></h3><p>When one overload is preferred, but others should exist, the less preferred ones can be marked with <span class="code">requires <span class="keyword">true</span></span>. This lifts one overload up out of the overload set for ambiguous matches, while leaving the rest to exist.</p><h3 data-number="6.1.2" id="Tag-type-forced-conversions-for-exact-matches"><span class="header-section-number">6.1.2</span> Tag type forced conversions for exact matches<a href="#Tag-type-forced-conversions-for-exact-matches" class="self-link"></a></h3><p><a href="https://godbolt.org/z/8qssnq8rf">https://godbolt.org/z/8qssnq8rf</a> and <a href="https://godbolt.org/z/xG7955hf9">https://godbolt.org/z/xG7955hf9</a> illustrate the idea of using a wrapping template to make one overload stand out.</p><h3 data-number="6.1.3" id="Explicitly-adding-a-function-to-disambiguate-manually"><span class="header-section-number">6.1.3</span> Explicitly adding a function to disambiguate manually<a href="#Explicitly-adding-a-function-to-disambiguate-manually" class="self-link"></a></h3><p><a href="https://godbolt.org/z/9zoGEh1cv">https://godbolt.org/z/9zoGEh1cv</a> demonstrates adding an overload that matches anything that isn't an exact match, which indirects to a function that hand-picks an overload.</p><h2 data-number="6.2" id="Construction"><span class="header-section-number">6.2</span> Construction<a href="#Construction" class="self-link"></a></h2><p><span class="code">std<span class="special">::</span>basic_string_view</span> offers a handful of constructors:</p><code><div class="code"><span class="keyword">constexpr</span> basic_string_view<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> str<span class="special">);</span> <span class="special">// (1)</span></div></code><p>The basic constructor from an unadorned <span class="code">charT<span class="special">*</span></span> risks taking a non-null-terminated string and searching for the null terminator. For <span class="code">zstring_view</span> this constructor is as safe as it is for <span class="code">string_view</span>, since we need to have a null terminator anyway.</p><code><div class="code"><span class="keyword">constexpr</span> basic_string_view<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> str<span class="special">,</span> size_type len<span class="special">);</span> <span class="special">// (2)</span></div></code><p>This constructor conceptually offers a O(1) construction time. For zstring_view we add a contract that asserts that <span class="code">str<span class="special">[</span>len<span class="special">]</span> <span class="special">==</span> <span class="special">'\</span>0<span class="special">'</span></span>.</p><code><div class="code"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> It<span class="special">,</span> <span class="keyword">class</span> End<span class="special">&gt;</span>
<span class="keyword">constexpr</span> basic_string_view<span class="special">(</span>It begin<span class="special">,</span> End end<span class="special">);</span> <span class="special">// (3)</span></div></code><p>This constructor is problematic to support, as we have to check the end iterator to ensure the string is null-terminated, but the end iterator cannot be assumed to be dereferencable.</p><code><div class="code"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> R<span class="special">&gt;</span>
<span class="keyword">constexpr</span> <span class="keyword">explicit</span> basic_string_view<span class="special">(</span>R<span class="special">&amp;&amp;</span> r<span class="special">);</span> <span class="special">// (4)</span></div></code><p>This constructor is difficult to support as well; we need to check that after the end of the range there is a null terminator, which is by definition accessing out of the range.</p><code><div class="code">basic_string_view<span class="special">(</span> std<span class="special">::</span>nullptr_t <span class="special">)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span> <span class="special">// (5)</span></div></code><p>We should not support constructing a string from nullptr.</p><h2 data-number="6.3" id="Member-functions-on--string_view--that-return-a--string_view-"><span class="header-section-number">6.3</span> Member functions on `string_view` that return a `string_view`<a href="#Member-functions-on--string_view--that-return-a--string_view-" class="self-link"></a></h2><p>In some cases the functions can be replicated on <span class="code">zstring_view</span> with the return type being a <span class="code">zstring_view</span>, while in some cases the return type loses the ability to guarantee null termination, and should still return a <span class="code">string_view</span>. The types are somewhat entangled.</p><h3 data-number="6.3.1" id="-substr-"><span class="header-section-number">6.3.1</span> `substr`<a href="#-substr-" class="self-link"></a></h3><p>The <span class="code">substr</span> function is changed from a single function with a default argument, to two functions, one with one and one with two arguments. The one-argument <span class="code">substr</span> always retains the end (identical to <span class="code">string_view</span>'s <span class="code">substr</span>) and returns a <span class="code">zstring_view</span>; the two-argument <span class="code">substr</span> at least in a conceptual sense chops off at least the null terminator from the end, and should always return a <span class="code">string_view</span>.</p><h3 data-number="6.3.2" id="-remove_prefix-"><span class="header-section-number">6.3.2</span> `remove_prefix`<a href="#-remove_prefix-" class="self-link"></a></h3><p><span class="code">remove_prefix</span> drops characters from the front of the string it's called on. Behavior fits.</p><h3 data-number="6.3.3" id="-remove_suffix-"><span class="header-section-number">6.3.3</span> `remove_suffix`<a href="#-remove_suffix-" class="self-link"></a></h3><p><span class="code">remove_suffix</span> changes the string in-situ, and as such is unimplementable on zstring_view. It should be a function marked as =delete with a reason pointing users to use the two-argument <span class="code">substr</span> function instead, which returns a <span class="code">string_view</span>.</p><h1 data-number="7" id="Bikeshedding"><span class="header-section-number">7</span> Bikeshedding<a href="#Bikeshedding" class="self-link"></a></h1><p>Null-terminated string view types are typically named <span class="code">zstring_view</span> (N3921, P3081, GSL) or <span class="code">cstring_view</span> (P1402). <span class="code">cstring_view</span> follows the <span class="code">std<span class="special">::</span>string<span class="special">::</span>c_str<span class="special">()</span></span> nomenclature while <span class="code">zstring_view</span> has some establishment and recognizability.</p><p>Github code search shows similar popularity between <a href="`cstring_view`">https://github.com/search?q=%2F%5Cbcstring_view%5Cb%2F%20language%3Ac%2B%2B%20-is%3Afork&type=code</a> (1.2k results as of the time of writing) and <a href="`zstring_view`">https://github.com/search?q=%2F%5Cbzstring_view%5Cb%2F+language%3Ac%2B%2B+-is%3Afork&type=code</a> (680 results as of the time of writing). In refreshing this paper, it appears that cstring_view has gained ~200 added results, while zstring_view only added 8, hinting at a popular preference for the former name.</p><h1 data-number="8" id="Reference-Implementation"><span class="header-section-number">8</span> Reference Implementation<a href="#Reference-Implementation" class="self-link"></a></h1><p>A reference implementation is at <a href="Jeremy's Github">https://github.com/jeremy-rifkin/zstring_view</a>.</p><h1 data-number="9" id="NVIDIA-Experience--moved-from-p3710-"><span class="header-section-number">9</span> NVIDIA Experience (moved from p3710)<a href="#NVIDIA-Experience--moved-from-p3710-" class="self-link"></a></h1><p>NVIDIA implemented <span class="code">zstring_view</span> independently, with almost identical features. This is described in <a href="P3710 zstring_view: a string_view with guaranteed null termination">https://wg21.link/p3710</a>, now merged into this paper. We also implemented some additional features described in <a href="P3566 You shall not pass char*">https://wg21.link/p3566</a>.</p><p>Ideally we wanted our input parameters to all be <span class="code">string_view</span> and all the output parameter to be <span class="code">zstring_view</span> (which gives more flexibility).</p><p>In practice, there are exceptions on both sides:</p><ul><li>When a null-terminated parameter is needed for internal reasons outside of our control, i.e. when interacting with system calls or third-party libraries, it's preferable to have a <span class="code">zstring_view</span> parameter.</li><li>When returning a part of an internal string, e.g. when extracting the file name from a full path, it's more convenient to just return a <span class="code">string_view</span>.</li></ul><p>Nonetheless, having a large codebase, we knew we couldn't just rewrite the entire codebase to apply this change, so we used <span class="code">zstring_view</span> as a tool for steering our codebase in the ideal direction described above.</p><p>Initially, we used as <span class="code">zstring_view</span> as a drop-in replacement for <span class="code"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span></span> parameters and return values of our APIs, without worrying too much wether or not the function expects a null terminator. As a sidenote, for this migration we asked our developers to be intentional in using <span class="code"><span class="special">.</span>data<span class="special">()</span></span> or <span class="code"><span class="special">.</span>c_str<span class="special">()</span></span>, and use <span class="code"><span class="special">.</span>data<span class="special">()</span></span> when a null-terminator is not expected, and only use <span class="code"><span class="special">.</span>c_str<span class="special">()</span></span> when the string is required to be terminated. If respected, this rule allows us to just try changing a parameter from <span class="code">zstring_view</span> to <span class="code">string_view</span> and verify wether or not a function is relying on some parameter to be null-terminated. This operation can be done incrementally, one function at a time.</p><p>Once this was done, we started from the "deepest" functions to analyze their usage, and replace their parameters <span class="code">zstring_view</span> to <span class="code">string_view</span>, or rewrite them to allow for <span class="code">string_view</span> parameters. We proceeded upwards in the call chain, and did the same. Again, this can be done in multiple passes.</p><p>What we observed is that, in some case, this might not only make the code safer, but also enable new optimizations.</p><p>Here follows an example of a parameter upgrade how we implemented these changes, step-by-step, with an example of how this can lead to more performant and safer code at the end of the process.</p><code><div class="code"><span class="keyword">void</span> f<span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> x<span class="special">)</span> <span class="special">{</span>
  external_library<span class="special">::</span>g1<span class="special">(</span>x<span class="special">);</span>
<span class="special">}</span>

<span class="keyword">void</span> f1<span class="special">()</span> <span class="special">{</span>
  std<span class="special">::</span>string a1 <span class="special">=</span> <span class="special">"</span>test<span class="special">";</span>
  f<span class="special">(</span>a1<span class="special">.</span>c_str<span class="special">());</span>
<span class="special">}</span>

<span class="keyword">void</span> f2<span class="special">()</span> <span class="special">{</span>
  <span class="keyword">constexpr</span> <span class="keyword">char</span> a2<span class="special">[]</span> <span class="special">=</span> <span class="special">"</span>test<span class="special">";</span>
  f<span class="special">(</span>a2<span class="special">);</span>
<span class="special">}</span>

<span class="keyword">void</span> f3<span class="special">()</span> <span class="special">{</span>
  <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> a3 <span class="special">=</span> <span class="special">"</span>test<span class="special">";</span>
  f<span class="special">(</span>a3<span class="special">);</span>
<span class="special">}</span>

<span class="keyword">void</span> f4<span class="special">()</span> <span class="special">{</span>
  string_view a4 <span class="special">=</span> <span class="special">"</span>abcde<span class="special">";</span>
  string_view subtext <span class="special">=</span> a4<span class="special">.</span>substr<span class="special">(</span>2<span class="special">,</span> 2<span class="special">);</span> <span class="comment">// no null terminator at the end of `subtext`</span><br>
  f<span class="special">(</span>string<span class="special">{</span>subtext<span class="special">});</span> <span class="comment">// create a temporary to add the terminator</span><br><span class="special">}</span></div></code><p>In this example, <span class="code">external_library<span class="special">::</span>g1</span> is a placeholder for some generic computation that happens on the string.</p><p>Initially, we update the API we will change f to:</p><code><div class="code"><span class="keyword">void</span> f<span class="special">(</span>zstring_view x<span class="special">)</span> <span class="special">{</span>
  external_library<span class="special">::</span>g1<span class="special">(</span>x<span class="special">.</span>c_str<span class="special">());</span>
<span class="special">}</span></div></code><p>All the functions now have well-defined memory ranges (no unbounded string).</p><p>We can now then look for alternatives, and find out there's a different API for the <span class="code">external_library<span class="special">::</span>g1</span> we can use, e.g. <span class="code">external_library<span class="special">::</span>g2<span class="special">(</span><span class="keyword">char</span><span class="special">*,</span> size_t<span class="special">)</span></span>, that doesn't require a null-terminated sequence.</p><code><div class="code"><span class="keyword">void</span> f<span class="special">(</span>string_view x<span class="special">)</span> <span class="special">{</span>
  external_library<span class="special">::</span>g2<span class="special">(</span>x<span class="special">.</span>data<span class="special">(),</span> x<span class="special">.</span>size<span class="special">());</span>
<span class="special">}</span></div></code><p>As next step, we can check all the usages, and see if we can get rid of some extra code, for example:</p><code><div class="code"><span class="keyword">void</span> f4<span class="special">()</span> <span class="special">{</span>
  string_view a4 <span class="special">=</span> <span class="special">"</span>abcde<span class="special">";</span>
  string_view subtext <span class="special">=</span> a4<span class="special">.</span>substr<span class="special">(</span>2<span class="special">,</span> 2<span class="special">);</span> <span class="comment">// no null terminator at the end of `subtext`</span><br>
  f<span class="special">(</span>subtext<span class="special">);</span> <span class="comment">// f now accepts a string_view, no need for temporary</span><br><span class="special">}</span></div></code><p>This results in a better-optimized code at the end (less need for temporary <span class="code">string</span>s).</p><p>NOTE: The sequence of changes in our codebase was different, because our codebase includes the changes proposed in <a href="P3566 You shall not pass char*">https://wg21.link/p3566</a>, so some of the intermediate steps relying on implicit <span class="code"><span class="keyword">char</span><span class="special">*</span></span> -&gt; <span class="code">string_view</span> and <span class="code"><span class="keyword">char</span><span class="special">*</span></span> -&gt; <span class="code">zstring_view</span> conversions require additional changes, and intermediate steps marking conversions with the proposed <span class="code">unsafe_length</span> tag.</p><h1 data-number="10" id="Standard-Library-Changes"><span class="header-section-number">10</span> Standard Library Changes<a href="#Standard-Library-Changes" class="self-link"></a></h1><p>There are a handful of interfaces in the standard library which take <span class="code"><span class="keyword">const</span> string<span class="special">&amp;</span></span> and really want a <span class="code">zstring_view</span> or possibly a <span class="code">string_view</span>. These include:</p><ul><li>Constructors for stdexcept types, <span class="code">system_error</span>, <span class="code">format_error</span>, <span class="code">ios_base<span class="special">::</span>failure</span>, and <span class="code">std<span class="special">::</span>filesystem<span class="special">::</span>filesystem_error</span></li><li>The <span class="code">stoi</span> family of functions</li><li><span class="code">random_device<span class="special">::</span>random_device</span></li><li>Lots of locale interfaces</li><li><span class="code">basic_filebuf<span class="special">::</span>open</span>, <span class="code">basic_ifstream<span class="special">::</span>basic_ifstream</span>, <span class="code">basic_ifstream<span class="special">::</span>open</span>, <span class="code">basic_ofstream<span class="special">::</span>basic_ofstream</span>, <span class="code">basic_ofstream<span class="special">::</span>open</span>, <span class="code">basic_fstream<span class="special">::</span>basic_fstream</span>,  and <span class="code">basic_fstream<span class="special">::</span>open</span></li></ul><p>There are further interfaces which take <span class="code"><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span></span> and could have overloads taking a <span class="code">zstring_view</span> or <span class="code">string_view</span>.</p><p>We do not propose any such changes in this paper but would like to investigate this in a follow-up paper.</p><h1 data-number="11" id="Polls"><span class="header-section-number">11</span> Polls<a href="#Polls" class="self-link"></a></h1><p>The first question to LEWG is, do we want to have the zstring_view type in the standard library? So far it looks like voting against the type leads to people implementing their own, including C++ committee members "implementing" their own zstring_view in wording. We also have a few direction questions with regards to either "fixing" string interface, or keeping the interfaces synchronized.</p><h2 data-number="11.1" id="We-encourage-further-work-on-the-zstring_view-proposal-for-the-Cpp29-timeframe-"><span class="header-section-number">11.1</span> We encourage further work on the zstring_view proposal for the C++29 timeframe.<a href="#We-encourage-further-work-on-the-zstring_view-proposal-for-the-Cpp29-timeframe-" class="self-link"></a></h2><p>If so, we will return at the next meeting (Kona 2025) with the wording worked out and checked with a Core representative, with the intent of merging zstring_view early in the C++29 cycle. If not, we will retire this paper.</p><h2 data-number="11.2" id="We-prefer-the-name--cstring_view-"><span class="header-section-number">11.2</span> We prefer the name `cstring_view`<a href="#We-prefer-the-name--cstring_view-" class="self-link"></a></h2><p>The bikeshedding mentioned above. At this point we can still choose which name to use. The authors have no preference.</p><ul><li><span class="code">cstring_view</span> is more common on Github at the time of writing, at a factor of about 2:1</li><li><span class="code">cstring_view</span> matches existing <span class="code">std<span class="special">::</span>string</span> interface nomenclature (<span class="code">c_str<span class="special">()</span></span>).</li><li><span class="code">zstring_view</span> is the most recently proposed name in <a href="P3081">https://wg21.link/p3081</a></li></ul><h2 data-number="11.3" id="We-prefer-zstring_view-to-remove-char_traits-from-its-interface-"><span class="header-section-number">11.3</span> We prefer zstring_view to remove char_traits from its interface.<a href="#We-prefer-zstring_view-to-remove-char_traits-from-its-interface-" class="self-link"></a></h2><p>SG16 has long held that char_traits offer no value and are sometimes abused. If possible they would propose to remove it altogether <a href="P3681">P3681</a>. This paper however is trying to add <span class="code">zstring_view</span> to the standard without changing the direction for char_traits, and as such it is not proposing to remove char_traits.</p><p>Removing it anyway would necessarily lose information on implicit conversion from std::string through std::zstring_view to std::string_view, as the char_traits that were present on the string are no longer possible to transfer to the string_view. There was a discussion in SG16 with regards to char_traits needing to be removed, needing to be kept, or whether no objection existed to retaining it for compatibility, and the following poll was taken:</p><p class="quote">Poll 1: P3655R0: No objection to use of std::char_traits for consistency and compatibility with std::string_view.</p><table><tbody><tr><td> SF </td><td> F </td><td> N </td><td> A </td><td> SA </td></tr><tr><td> 7 </td><td> 1 </td><td> 0 </td><td> 0 </td><td> 0 </td></tr></tbody></table><p class="quote">Strong consensus. Attendees: 8 (no abstentions)</p><p>The paper authors hold no strong opinion on whether char_traits should be kept or removed. Pragmatically we propose to keep char_traits to make the conversion through zstring_view lossless, and to treat removal of char_traits support as a uniform thing to be applied to all string types. <a href="P3681">P3681</a> disagrees, however, and we hope to see it up for discussion to reduce user-visible churn.</p><h2 data-number="11.4" id="We-prefer-the-zstring_view-interface-to-add-an-array-constructor"><span class="header-section-number">11.4</span> We prefer the zstring_view interface to add an array constructor<a href="#We-prefer-the-zstring_view-interface-to-add-an-array-constructor" class="self-link"></a></h2><code><div class="code"><span class="keyword">template</span> <span class="special">&lt;</span>size_t N<span class="special">&gt;</span>
<span class="keyword">consteval</span> basic_zstring_view<span class="special">(</span><span class="keyword">const</span> charT <span class="special">(</span><span class="special">&amp;</span>str<span class="special">)[</span>N<span class="special">]);</span></div></code><p>The advantage of adding this function is that it is a clean constructor to convert from a string literal with compile-time known size. The downsides are that it will create an interface difference between <span class="code">string_view</span> and <span class="code">zstring_view</span>.</p><h2 data-number="11.5" id="We-prefer-to-disallow-contained-NULs-"><span class="header-section-number">11.5</span> We prefer to disallow contained NULs <a href="#We-prefer-to-disallow-contained-NULs-" class="self-link"></a></h2><p>String and string_view both support having a string with embedded NUL characters. On one hand it makes complete sense to do the same for zstring_view. On the other hand, the value of zstring_view lies in knowing it has a null terminator at <span class="code">size<span class="special">()</span></span>, and while allowing embedded NULs would not strictly violate that - there still is a NUL terminator there - it would logically break it, as there would be a NUL before that that effectively terminates the string. </p><p>This gives rise to the possibility for bugs where strings are being used by their <span class="code">strlen<span class="special">(</span>x<span class="special">.</span>c_str<span class="special">())</span></span> length, and elsewhere by their <span class="code">x<span class="special">.</span>size<span class="special">()</span></span>. These things are likely enough to have <a href="CWE-135: Incorrect Calculation of Multi-Byte String Length">https://cwe.mitre.org/data/definitions/135.html</a> and <a href="CWE-179: Incorrect Behavior Order: Early Validation">https://cwe.mitre.org/data/definitions/179.html</a>, quote:</p><p class="quote">An attacker could include dangerous input that bypasses validation protection mechanisms which can be used to launch various attacks including injection attacks, execute arbitrary code or cause other unintended behavior.</p><p>Consider the following call:</p><code><div class="code">std<span class="special">::</span>zstring_view user_command <span class="special">=</span> <span class="special">"</span>ls<span class="special">\</span>0rm <span class="special">-</span>rf <span class="special">/";</span>
validate_command<span class="special">(</span>user_command<span class="special">.</span>c_str<span class="special">());</span> <span class="comment">// older validation function that does its own strlen()</span><br>evaluate_command<span class="special">(</span>user_command<span class="special">);</span> <span class="special">// newer function that uses user_command.size()</span></div></code><p>We can prevent these bugs at this stage by disallowing contained NULs in the NUL-terminated string view type. But it is a breaking change to existing expectation.</p><p>A strong argument against is that constructing a <span class="code">zstring_view</span> from this string literal will behave differently than constructing a <span class="code">string_view</span> would, and the invariant that <span class="code">zstring_view</span> is null-terminated is not broken with an embedded NUL.</p><h1 data-number="12" id="Wording"><span class="header-section-number">12</span> Wording<a href="#Wording" class="self-link"></a></h1><p>This wording section is currently mostly high-level and synopsis changes. We defer full wording until feedback from LEWG.</p><p>Borrowing extensively from existing <span class="code">string_view</span> wording.</p><p>Add to <span class="code"><span class="special">[</span>format<span class="special">.</span>formatter<span class="special">.</span>spec<span class="special">]</span></span> 2.2:</p><code><div class="code"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> traits<span class="special">&gt;</span>
  <span class="keyword">struct</span> formatter<span class="special">&lt;</span>basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span><span class="special">,</span> charT<span class="special">&gt;</span><span class="special">;</span></div></code><p>Add to <span class="code"><span class="special">[</span>format<span class="special">.</span>formatter<span class="special">.</span>spec<span class="special">]</span></span> 4.1:</p><code><div class="code"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> traits<span class="special">&gt;</span>
  <span class="keyword">struct</span> formatter<span class="special">&lt;</span>basic_zstring_view<span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span> traits<span class="special">&gt;</span><span class="special">,</span> <span class="keyword">wchar_t</span><span class="special">&gt;</span><span class="special">;</span></div></code><p>Update <a href="string.view.general">string.view.general</a> note 1 to mention conversion from <span class="code">basic_zstring_view</span> to <span class="code">basic_string_view</span>.</p><p>Add to <a href="basic.string.general">basic.string.general</a>:</p><code><div class="code">    <span class="keyword">constexpr</span> <span class="keyword">operator</span> basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span></div></code><p>Wording on additions deferred until a later revision.</p><h2 data-number="12.1" id="Zstring-View-Classes--zstring-view-"><span class="header-section-number">12.1</span> Zstring View Classes [zstring.view]<a href="#Zstring-View-Classes--zstring-view-" class="self-link"></a></h2><h3 data-number="12.1.1" id="General--zstring-view-general-"><span class="header-section-number">12.1.1</span> General [zstring.view.general]<a href="#General--zstring-view-general-" class="self-link"></a></h3><p>The class template basic_zstring_view describes an object that can refer to a constant contiguous sequence of char-like (<a href="strings.general">strings.general</a>) objects with the first element of the sequence at position zero. In the rest of <a href="string.view">string.view</a>, the type of the char-like objects held in a <span class="code">basic_string_view</span> object is designated by <span class="code">charT</span>.</p><p>In all cases, <span class="code"><span class="special">[</span>data<span class="special">(),</span> data<span class="special">()</span> <span class="special">+</span> size<span class="special">()]</span></span> is a valid range and <span class="code">data<span class="special">()</span> <span class="special">+</span> size<span class="special">()</span></span> points at an object with value <span class="code">charT<span class="special">()</span></span> (a "null terminator").</p><p>[Note 1: <span class="code">basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> <span class="special">...</span><span class="special">&gt;</span></span> is primarily useful when working with C APIs which expect null terminated strings. - end note]</p><h4 data-number="12.1.1.1" id="Header---zstring_view---synopsis--zstring-view-synop-"><span class="header-section-number">12.1.1.1</span> Header `<zstring_view>` synopsis [zstring.view.synop]<a href="#Header---zstring_view---synopsis--zstring-view-synop-" class="self-link"></a></h4><code><div class="code"><span class="comment">// mostly freestanding</span><br><span class="special">#</span>include <span class="special">&lt;</span>compare<span class="special">&gt;</span>              <span class="comment">// see [compare.syn]</span><br>
<span class="keyword">namespace</span> std <span class="special">{</span>
  <span class="comment">// [zstring.view.template], class template basic_zstring_view</span><br>  <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> charT<span class="special">,</span> <span class="keyword">class</span> traits <span class="special">=</span> char_traits<span class="special">&lt;</span>charT<span class="special">&gt;&gt;</span>
  <span class="keyword">class</span> basic_zstring_view<span class="special">;</span>                                              <span class="comment">// partially freestanding</span><br>
  <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> charT<span class="special">,</span> <span class="keyword">class</span> traits<span class="special">&gt;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> ranges<span class="special">::</span>enable_view<span class="special">&lt;</span>basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;&gt;</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span>
  <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> charT<span class="special">,</span> <span class="keyword">class</span> traits<span class="special">&gt;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> ranges<span class="special">::</span>enable_borrowed_range<span class="special">&lt;</span>basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;&gt;</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span>

  <span class="comment">// [zstring.view.comparison], non-member comparison functions</span><br>  <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> charT<span class="special">,</span> <span class="keyword">class</span> traits<span class="special">&gt;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">==(</span>basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> x<span class="special">,</span>
                              type_identity_t<span class="special">&lt;</span>basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;&gt;</span> y<span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
  <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> charT<span class="special">,</span> <span class="keyword">class</span> traits<span class="special">&gt;</span>
    <span class="keyword">constexpr</span> <span class="comment">/* see below */</span><br> <span class="keyword">operator</span><span class="special">&lt;</span><span class="special">=</span><span class="special">&gt;</span><span class="special">(</span>basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> x<span class="special">,</span>
                              type_identity_t<span class="special">&lt;</span>basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;&gt;</span> y<span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>

  <span class="comment">// [zstring.view.io], inserters and extractors</span><br>  <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> charT<span class="special">,</span> <span class="keyword">class</span> traits<span class="special">&gt;</span>
    basic_ostream<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;&amp;</span>
      <span class="keyword">operator</span><span class="special">&lt;&lt;</span><span class="special">(</span>basic_ostream<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;&amp;</span> os<span class="special">,</span>
                 basic_zstring_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> str<span class="special">);</span>                 <span class="comment">// hosted</span><br>
  <span class="comment">// basic_zstring_view typedef-names</span><br>  <span class="keyword">using</span> zstring_view    <span class="special">=</span> basic_zstring_view<span class="special">&lt;</span><span class="keyword">char</span><span class="special">&gt;</span><span class="special">;</span>
  <span class="keyword">using</span> u8zstring_view  <span class="special">=</span> basic_zstring_view<span class="special">&lt;</span><span class="keyword">char8_t</span><span class="special">&gt;</span><span class="special">;</span>
  <span class="keyword">using</span> u16zstring_view <span class="special">=</span> basic_zstring_view<span class="special">&lt;</span><span class="keyword">char16_t</span><span class="special">&gt;</span><span class="special">;</span>
  <span class="keyword">using</span> u32zstring_view <span class="special">=</span> basic_zstring_view<span class="special">&lt;</span><span class="keyword">char32_t</span><span class="special">&gt;</span><span class="special">;</span>
  <span class="keyword">using</span> wzstring_view   <span class="special">=</span> basic_zstring_view<span class="special">&lt;</span><span class="keyword">wchar_t</span><span class="special">&gt;</span><span class="special">;</span>

  <span class="comment">// [zstring.view.hash], hash support</span><br>  <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> T<span class="special">&gt;</span> <span class="keyword">struct</span> hash<span class="special">;</span>
  <span class="keyword">template</span><span class="special">&lt;&gt;</span> <span class="keyword">struct</span> hash<span class="special">&lt;</span>zstring_view<span class="special">&gt;</span><span class="special">;</span>
  <span class="keyword">template</span><span class="special">&lt;&gt;</span> <span class="keyword">struct</span> hash<span class="special">&lt;</span>u8zstring_view<span class="special">&gt;</span><span class="special">;</span>
  <span class="keyword">template</span><span class="special">&lt;&gt;</span> <span class="keyword">struct</span> hash<span class="special">&lt;</span>u16zstring_view<span class="special">&gt;</span><span class="special">;</span>
  <span class="keyword">template</span><span class="special">&lt;&gt;</span> <span class="keyword">struct</span> hash<span class="special">&lt;</span>u32zstring_view<span class="special">&gt;</span><span class="special">;</span>
  <span class="keyword">template</span><span class="special">&lt;&gt;</span> <span class="keyword">struct</span> hash<span class="special">&lt;</span>wzstring_view<span class="special">&gt;</span><span class="special">;</span>

  <span class="keyword">inline</span> <span class="keyword">namespace</span> literals <span class="special">{</span>
    <span class="keyword">inline</span> <span class="keyword">namespace</span> zstring_view_literals <span class="special">{</span>
      <span class="comment">// [zstring.view.literals], suffix for basic_zstring_view literals</span><br>      <span class="keyword">constexpr</span> zstring_view    <span class="keyword">operator</span><span class="special">""</span>zsv<span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> str<span class="special">,</span> size_t len<span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
      <span class="keyword">constexpr</span> u8zstring_view  <span class="keyword">operator</span><span class="special">""</span>zsv<span class="special">(</span><span class="keyword">const</span> <span class="keyword">char8_t</span><span class="special">*</span> str<span class="special">,</span> size_t len<span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
      <span class="keyword">constexpr</span> u16zstring_view <span class="keyword">operator</span><span class="special">""</span>zsv<span class="special">(</span><span class="keyword">const</span> <span class="keyword">char16_t</span><span class="special">*</span> str<span class="special">,</span> size_t len<span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
      <span class="keyword">constexpr</span> u32zstring_view <span class="keyword">operator</span><span class="special">""</span>zsv<span class="special">(</span><span class="keyword">const</span> <span class="keyword">char32_t</span><span class="special">*</span> str<span class="special">,</span> size_t len<span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
      <span class="keyword">constexpr</span> wzstring_view   <span class="keyword">operator</span><span class="special">""</span>zsv<span class="special">(</span><span class="keyword">const</span> <span class="keyword">wchar_t</span><span class="special">*</span> str<span class="special">,</span> size_t len<span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="special">}</span>
  <span class="special">}</span>
<span class="special">}</span></div></code><h3 data-number="12.1.2" id="Class-template-basic_zstring_view--zstring-view-template-"><span class="header-section-number">12.1.2</span> Class template basic_zstring_view [zstring.view.template]<a href="#Class-template-basic_zstring_view--zstring-view-template-" class="self-link"></a></h3><h4 data-number="12.1.2.1" id="General--zstring-view-template-general-"><span class="header-section-number">12.1.2.1</span> General [zstring.view.template.general]<a href="#General--zstring-view-template-general-" class="self-link"></a></h4><code><div class="code"><span class="keyword">namespace</span> std <span class="special">{</span>
  <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> charT<span class="special">,</span> <span class="keyword">class</span> traits <span class="special">=</span> char_traits<span class="special">&lt;</span>charT<span class="special">&gt;&gt;</span>
  <span class="keyword">class</span> basic_zstring_view <span class="special">{</span>
  <span class="keyword">public</span><span class="special">:</span>
    <span class="comment">// types</span><br>    <span class="keyword">using</span> traits_type            <span class="special">=</span> traits<span class="special">;</span>
    <span class="keyword">using</span> value_type             <span class="special">=</span> charT<span class="special">;</span>
    <span class="keyword">using</span> pointer                <span class="special">=</span> value_type<span class="special">*;</span>
    <span class="keyword">using</span> const_pointer          <span class="special">=</span> <span class="keyword">const</span> value_type<span class="special">*;</span>
    <span class="keyword">using</span> reference              <span class="special">=</span> value_type<span class="special">&amp;</span><span class="special">;</span>
    <span class="keyword">using</span> const_reference        <span class="special">=</span> <span class="keyword">const</span> value_type<span class="special">&amp;</span><span class="special">;</span>
    <span class="keyword">using</span> const_iterator         <span class="special">=</span> implementation<span class="special">-</span>defined<span class="special">;</span> <span class="comment">// see [zstring.view.iterators]</span><br>    <span class="keyword">using</span> iterator               <span class="special">=</span> const_iterator<span class="special">;</span>
    <span class="keyword">using</span> const_reverse_iterator <span class="special">=</span> reverse_iterator<span class="special">&lt;</span>const_iterator<span class="special">&gt;</span><span class="special">;</span>
    <span class="keyword">using</span> reverse_iterator       <span class="special">=</span> const_reverse_iterator<span class="special">;</span>
    <span class="keyword">using</span> size_type              <span class="special">=</span> size_t<span class="special">;</span>
    <span class="keyword">using</span> difference_type        <span class="special">=</span> ptrdiff_t<span class="special">;</span>
    <span class="keyword">static</span> <span class="keyword">constexpr</span> size_type npos <span class="special">=</span> size_type<span class="special">(-</span>1<span class="special">);</span>

    <span class="comment">// [zstring.view.cons], construction and assignment</span><br>    <span class="keyword">constexpr</span> basic_zstring_view<span class="special">()</span> <span class="keyword">noexcept</span><span class="special">;</span>
    basic_zstring_view<span class="special">(</span><span class="keyword">const</span> basic_zstring_view<span class="special">&amp;</span><span class="special">)</span> <span class="keyword">noexcept</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span>
    basic_zstring_view<span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> basic_zstring_view<span class="special">&amp;</span><span class="special">)</span> <span class="keyword">noexcept</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span>
    <span class="keyword">constexpr</span> basic_zstring_view<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> str<span class="special">)</span> <span class="keyword">noexcept</span>
              <span class="keyword">pre</span><span class="special">(</span>str <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> basic_zstring_view<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> str<span class="special">,</span> size_type len<span class="special">)</span> <span class="keyword">noexcept</span>
              <span class="keyword">pre</span> <span class="special">(</span>str <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">)</span> 
              <span class="keyword">pre</span> <span class="special">(</span>str<span class="special">[</span>len<span class="special">]</span> <span class="special">==</span> <span class="special">'\</span>0<span class="special">');</span>
    <span class="keyword">template</span> <span class="special">&lt;</span>size_t N<span class="special">&gt;</span>
    <span class="keyword">constexpr</span> basic_zstring_view<span class="special">(</span><span class="keyword">const</span> charT <span class="special">(</span><span class="special">&amp;</span>str<span class="special">)[</span>N<span class="special">])</span> <span class="keyword">noexcept</span>
              <span class="keyword">pre</span> <span class="special">(</span>traits<span class="special">::</span>find<span class="special">(</span>str<span class="special">,</span> N<span class="special">,</span> <span class="special">'\</span>0<span class="special">')</span> <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    basic_zstring_view<span class="special">(</span>nullptr_t<span class="special">)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>

    <span class="comment">// [zstring.view.iterators], iterator support</span><br>    <span class="keyword">constexpr</span> const_iterator begin<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_iterator end<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_iterator cbegin<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_iterator cend<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_reverse_iterator rbegin<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_reverse_iterator rend<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_reverse_iterator crbegin<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_reverse_iterator crend<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>

    <span class="comment">// [zstring.view.capacity], capacity</span><br>    <span class="keyword">constexpr</span> size_type size<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type length<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type max_size<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="special">[[</span>nodiscard<span class="special">]]</span> <span class="keyword">constexpr</span> <span class="keyword">bool</span> empty<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>

    <span class="comment">// [zstring.view.access], element access</span><br>    <span class="keyword">constexpr</span> const_reference <span class="keyword">operator</span><span class="special">[](</span>size_type pos<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>pos <span class="special">&lt;</span><span class="special">=</span> size<span class="special">());</span>
    <span class="keyword">constexpr</span> const_reference at<span class="special">(</span>size_type pos<span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_reference front<span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_reference back<span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_pointer data<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> const_pointer c_str<span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>

    <span class="keyword">operator</span> basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>

    <span class="comment">// [zstring.view.modifiers], modifiers</span><br>    <span class="keyword">constexpr</span> <span class="keyword">void</span> remove_prefix<span class="special">(</span>size_type n<span class="special">);</span>
    <span class="keyword">constexpr</span> <span class="keyword">void</span> remove_suffix<span class="special">(</span>size_type n<span class="special">)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">("</span>cannot remove_suffix in<span class="special">-</span>place on zstring_view <span class="keyword">while</span> retaining null terminator<span class="special">.</span> Use substr instead<span class="special">.");</span>
    <span class="keyword">constexpr</span> <span class="keyword">void</span> swap<span class="special">(</span>basic_zstring_view<span class="special">&amp;</span> s<span class="special">)</span> <span class="keyword">noexcept</span><span class="special">;</span>

    <span class="comment">// [zstring.view.ops], zstring operations</span><br>    <span class="keyword">constexpr</span> size_type copy<span class="special">(</span>charT<span class="special">*</span> s<span class="special">,</span> size_type n<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>

    <span class="keyword">constexpr</span> basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> substr<span class="special">(</span>size_type pos <span class="special">=</span> 0<span class="special">,</span> size_type n <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>

    <span class="keyword">constexpr</span> <span class="keyword">int</span> compare<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> s<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">int</span> compare<span class="special">(</span>size_type pos1<span class="special">,</span> size_type n1<span class="special">,</span> basic_zstring_view s<span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">int</span> compare<span class="special">(</span>size_type pos1<span class="special">,</span> size_type n1<span class="special">,</span> basic_zstring_view s<span class="special">,</span>
                          size_type pos2<span class="special">,</span> size_type n2<span class="special">)</span> <span class="keyword">const</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">int</span> compare<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> <span class="keyword">int</span> compare<span class="special">(</span>size_type pos1<span class="special">,</span> size_type n1<span class="special">,</span> <span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> <span class="keyword">int</span> compare<span class="special">(</span>size_type pos1<span class="special">,</span> size_type n1<span class="special">,</span> <span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type n2<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>

    <span class="keyword">constexpr</span> <span class="keyword">bool</span> starts_with<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> x<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> starts_with<span class="special">(</span>charT x<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> starts_with<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> x<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>x <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> ends_with<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> x<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> ends_with<span class="special">(</span>charT x<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> ends_with<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> x<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>x <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>

    <span class="keyword">constexpr</span> <span class="keyword">bool</span> contains<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> x<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> contains<span class="special">(</span>charT x<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> <span class="keyword">bool</span> contains<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> x<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>x <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>

    <span class="comment">// [zstring.view.find], searching</span><br>    <span class="keyword">constexpr</span> size_type find<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> s<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find<span class="special">(</span>charT c<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos<span class="special">,</span> size_type n<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type find<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type rfind<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> s<span class="special">,</span> size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type rfind<span class="special">(</span>charT c<span class="special">,</span> size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type rfind<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos<span class="special">,</span> size_type n<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type rfind<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>

    <span class="keyword">constexpr</span> size_type find_first_of<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> s<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find_first_of<span class="special">(</span>charT c<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find_first_of<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos<span class="special">,</span> size_type n<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type find_first_of<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type find_last_of<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> s<span class="special">,</span> size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find_last_of<span class="special">(</span>charT c<span class="special">,</span> size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find_last_of<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos<span class="special">,</span> size_type n<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type find_last_of<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type find_first_not_of<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> s<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find_first_not_of<span class="special">(</span>charT c<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find_first_not_of<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos<span class="special">,</span>
                                          size_type n<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type find_first_not_of<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos <span class="special">=</span> 0<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type find_last_not_of<span class="special">(</span>basic_string_view<span class="special">&lt;</span>charT<span class="special">,</span> traits<span class="special">&gt;</span> s<span class="special">,</span>
                                         size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find_last_not_of<span class="special">(</span>charT c<span class="special">,</span> size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span><span class="special">;</span>
    <span class="keyword">constexpr</span> size_type find_last_not_of<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos<span class="special">,</span>
                                         size_type n<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>
    <span class="keyword">constexpr</span> size_type find_last_not_of<span class="special">(</span><span class="keyword">const</span> charT<span class="special">*</span> s<span class="special">,</span> size_type pos <span class="special">=</span> npos<span class="special">)</span> <span class="keyword">const</span>
              <span class="keyword">pre</span> <span class="special">(</span>s <span class="special">!=</span> <span class="keyword">nullptr</span><span class="special">);</span>

  <span class="keyword">private</span><span class="special">:</span>
    const_pointer data_<span class="special">;</span>        <span class="comment">// exposition only</span><br>    size_type size_<span class="special">;</span>            <span class="comment">// exposition only</span><br>  <span class="special">};</span>
<span class="special">}</span></div></code><p>Wording on members deferred until a later revision.</p></body></html>
