There was a paper submitted before Kona: p3862r0 Postpone
basic_string::subview and wait for cstring_view [1],
that according to github papers status [2] have also NB comment. I was not
able to locale the comment thou.
So maybe it would be good to have this as patch series for string_view
(that would contain feature test macro) and then string,
so we can revert later?


[1] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3862r0.html#
[2] https://github.com/cplusplus/papers/issues/2466

On Thu, Nov 20, 2025 at 7:23 PM Jonathan Wakely <[email protected]> wrote:

> On Fri, 21 Nov 2025 at 01:50 +0800, Yuao Ma wrote:
> >Hi all,
> >
> >This patch implements P3044R2 by adding a subview function for string
> >and string_view. The implementation delegates directly to substr.
> >Tested on x86_64-linux.
> >Also, could you please help review my other patch regarding P3223R2 at
> >https://gcc.gnu.org/pipermail/libstdc++/2025-November/064369.html?
>
> Ah, I meant to follow up about that. It casues a test failure in C++26
> mode:
>
> PASS: 27_io/basic_istream/ignore/char/93672.cc  -std=gnu++26 (test for
> excess errors)
> FAIL: 27_io/basic_istream/ignore/char/93672.cc  -std=gnu++26 execution test
>
> The test probably just needs to be adjusted, as it was testing the
> previous workaround that I put in place for the problem with
> istream::ignore.
>
>
> >Thanks,
> >Yuao
>
> >From 6cf50b0e5a2fc1ca6814dbc4555c543c690d300a Mon Sep 17 00:00:00 2001
> >From: Yuao Ma <[email protected]>
> >Date: Fri, 21 Nov 2025 01:42:51 +0800
> >Subject: [PATCH] libstdc++: implement P3044R2 - sub-string_view from
> string
> >
> >libstdc++-v3/ChangeLog:
> >
> >       * include/bits/basic_string.h: Add subview.
> >       * include/bits/version.def: Add string_subview FTM.
> >       * include/bits/version.h: Regenerate.
> >       * include/std/string: Add FTM.
> >       * include/std/string_view: Add subview.
> >       * testsuite/21_strings/basic_string/operations/subview/char.cc:
> New test.
> >       * testsuite/21_strings/basic_string/operations/subview/wchar_t.cc:
> New test.
> >       *
> testsuite/21_strings/basic_string_view/operations/subview/char.cc: New test.
> >       *
> testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc: New
> test.
> >---
> > libstdc++-v3/include/bits/basic_string.h      | 19 +++++++
> > libstdc++-v3/include/bits/version.def         |  9 ++++
> > libstdc++-v3/include/bits/version.h           | 10 ++++
> > libstdc++-v3/include/std/string               |  1 +
> > libstdc++-v3/include/std/string_view          | 10 +++-
> > .../basic_string/operations/subview/char.cc   | 46 +++++++++++++++++
> > .../operations/subview/wchar_t.cc             | 46 +++++++++++++++++
> > .../operations/subview/char.cc                | 50 ++++++++++++++++++
> > .../operations/subview/wchar_t.cc             | 51 +++++++++++++++++++
> > 9 files changed, 241 insertions(+), 1 deletion(-)
> > create mode 100644
> libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
> > create mode 100644
> libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
> > create mode 100644
> libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
> > create mode 100644
> libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
> >
> >diff --git a/libstdc++-v3/include/bits/basic_string.h
> b/libstdc++-v3/include/bits/basic_string.h
> >index c4b6b1064a9..e87eb93e286 100644
> >--- a/libstdc++-v3/include/bits/basic_string.h
> >+++ b/libstdc++-v3/include/bits/basic_string.h
> >@@ -3442,6 +3442,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
> >       { return basic_string(*this,
> >                           _M_check(__pos, "basic_string::substr"), __n);
> }
> >
> >+#ifdef __glibcxx_string_subview // >= C++26
> >+      /**
> >+       *  @brief  Get a subview.
> >+       *  @param __pos  Index of first character (default 0).
> >+       *  @param __n  Number of characters in subview (default
> remainder).
> >+       *  @return  The subview.
> >+       *  @throw  std::out_of_range  If __pos > size().
> >+       *
> >+       *  Construct and return a subview using the @a __n characters
> starting
> >+       *  at @a __pos.  If the string is too short, use the remainder of
> the
> >+       *  characters.  If @a __pos is beyond the end of the string,
> >+       *  out_of_range is thrown.
> >+      */
> >+      _GLIBCXX_NODISCARD constexpr
>
> There's no need to use _GLIBCXX_NODISCARD for C++26 code, you can just
> use [[nodiscard]]. I can make that change before pushing though.
>
> >+      basic_string_view<_CharT, _Traits>
> >+      subview(size_type __pos = 0, size_type __n = npos) const
> >+      { return __sv_type(*this).subview(__pos, __n); }
> >+#endif
> >+
> >       /**
> >        *  @brief  Compare to a string.
> >        *  @param __str  String to compare against.
> >diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> >index 29ecf15c7e3..b5575d2399f 100644
> >--- a/libstdc++-v3/include/bits/version.def
> >+++ b/libstdc++-v3/include/bits/version.def
> >@@ -1934,6 +1934,15 @@ ftms = {
> >   };
> > };
> >
> >+ftms = {
> >+  name = string_subview;
> >+  values = {
> >+    v = 202506;
> >+    cxxmin = 26;
> >+    hosted = yes;
> >+  };
> >+};
> >+
> > ftms = {
> >   name = to_underlying;
> >   values = {
> >diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> >index 5901d27113d..413da56b088 100644
> >--- a/libstdc++-v3/include/bits/version.h
> >+++ b/libstdc++-v3/include/bits/version.h
> >@@ -2161,6 +2161,16 @@
> > #endif /* !defined(__cpp_lib_string_resize_and_overwrite) */
> > #undef __glibcxx_want_string_resize_and_overwrite
> >
> >+#if !defined(__cpp_lib_string_subview)
> >+# if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
> >+#  define __glibcxx_string_subview 202506L
> >+#  if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_string_subview)
> >+#   define __cpp_lib_string_subview 202506L
> >+#  endif
> >+# endif
> >+#endif /* !defined(__cpp_lib_string_subview) */
> >+#undef __glibcxx_want_string_subview
> >+
> > #if !defined(__cpp_lib_to_underlying)
> > # if (__cplusplus >= 202100L)
> > #  define __glibcxx_to_underlying 202102L
> >diff --git a/libstdc++-v3/include/std/string
> b/libstdc++-v3/include/std/string
> >index 97ded057a87..918b4158b47 100644
> >--- a/libstdc++-v3/include/std/string
> >+++ b/libstdc++-v3/include/std/string
> >@@ -63,6 +63,7 @@
> > #define __glibcxx_want_erase_if
> > #define __glibcxx_want_nonmember_container_access
> > #define __glibcxx_want_string_resize_and_overwrite
> >+#define __glibcxx_want_string_subview
> > #define __glibcxx_want_string_udls
> > #define __glibcxx_want_to_string
> > #include <bits/version.h>
> >diff --git a/libstdc++-v3/include/std/string_view
> b/libstdc++-v3/include/std/string_view
> >index 842f6ad89af..b226544fa6f 100644
> >--- a/libstdc++-v3/include/std/string_view
> >+++ b/libstdc++-v3/include/std/string_view
> >@@ -40,9 +40,10 @@
> > #define __glibcxx_want_constexpr_char_traits
> > #define __glibcxx_want_constexpr_string_view
> > #define __glibcxx_want_freestanding_string_view
> >-#define __glibcxx_want_string_view
> > #define __glibcxx_want_starts_ends_with
> > #define __glibcxx_want_string_contains
> >+#define __glibcxx_want_string_subview
> >+#define __glibcxx_want_string_view
> > #include <bits/version.h>
> >
> > #if __cplusplus >= 201703L
> >@@ -342,6 +343,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >       return basic_string_view{_M_str + __pos, __rlen};
> >       }
> >
> >+#ifdef __glibcxx_string_subview // >= C++26
> >+      [[nodiscard]]
> >+      constexpr basic_string_view
> >+      subview(size_type __pos = 0, size_type __n = npos) const
> >+      { return substr(__pos, __n); }
> >+#endif
> >+
> >       [[nodiscard]]
> >       constexpr int
> >       compare(basic_string_view __str) const noexcept
> >diff --git
> a/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
> b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
> >new file mode 100644
> >index 00000000000..c384948cc52
> >--- /dev/null
> >+++
> b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
> >@@ -0,0 +1,46 @@
> >+// { dg-do run { target c++26 } }
> >+
> >+#include <stdexcept>
> >+#include <string>
> >+#include <string_view>
> >+#include <testsuite_hooks.h>
> >+
> >+void test01(void) {
> >+  typedef std::string::size_type csize_type;
> >+  typedef std::string::const_reference cref;
> >+  typedef std::string::reference ref;
> >+  csize_type csz01;
> >+
> >+  const char str_lit01[] = "rockaway, pacifica";
> >+  const std::string str01(str_lit01);
> >+  std::string_view str02;
> >+
> >+  csz01 = str01.size();
> >+  str02 = str01.subview(0, 1);
> >+  VERIFY(str02 == "r");
> >+  str02 = str01.subview(10);
> >+  VERIFY(str02 == "pacifica");
> >+
> >+  try {
> >+    str02 = str01.subview(csz01 + 1);
> >+    VERIFY(false);
> >+  } catch (std::out_of_range &fail) {
> >+    VERIFY(true);
> >+  } catch (...) {
> >+    VERIFY(false);
> >+  }
> >+
> >+  try {
> >+    str02 = str01.subview(csz01);
> >+    VERIFY(str02.size() == 0);
> >+  } catch (std::out_of_range &fail) {
> >+    VERIFY(false);
> >+  } catch (...) {
> >+    VERIFY(false);
> >+  }
> >+}
> >+
> >+int main() {
> >+  test01();
> >+  return 0;
> >+}
> >diff --git
> a/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
> b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
> >new file mode 100644
> >index 00000000000..3b8e6a87fe6
> >--- /dev/null
> >+++
> b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
> >@@ -0,0 +1,46 @@
> >+// { dg-do run { target c++26 } }
> >+
> >+#include <stdexcept>
> >+#include <string>
> >+#include <string_view>
> >+#include <testsuite_hooks.h>
> >+
> >+void test01(void) {
> >+  typedef std::wstring::size_type csize_type;
> >+  typedef std::wstring::const_reference cref;
> >+  typedef std::wstring::reference ref;
> >+  csize_type csz01;
> >+
> >+  const wchar_t str_lit01[] = L"rockaway, pacifica";
> >+  const std::wstring str01(str_lit01);
> >+  std::wstring_view str02;
> >+
> >+  csz01 = str01.size();
> >+  str02 = str01.subview(0, 1);
> >+  VERIFY(str02 == L"r");
> >+  str02 = str01.subview(10);
> >+  VERIFY(str02 == L"pacifica");
> >+
> >+  try {
> >+    str02 = str01.subview(csz01 + 1);
> >+    VERIFY(false);
> >+  } catch (std::out_of_range &fail) {
> >+    VERIFY(true);
> >+  } catch (...) {
> >+    VERIFY(false);
> >+  }
> >+
> >+  try {
> >+    str02 = str01.subview(csz01);
> >+    VERIFY(str02.size() == 0);
> >+  } catch (std::out_of_range &fail) {
> >+    VERIFY(false);
> >+  } catch (...) {
> >+    VERIFY(false);
> >+  }
> >+}
> >+
> >+int main() {
> >+  test01();
> >+  return 0;
> >+}
> >diff --git
> a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
> b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
> >new file mode 100644
> >index 00000000000..f0ce145b45b
> >--- /dev/null
> >+++
> b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
> >@@ -0,0 +1,50 @@
> >+// { dg-do run { target c++26 } }
> >+#include <string_view>
> >+#include <testsuite_hooks.h>
> >+
> >+#if __STDC_HOSTED__
> >+#include <stdexcept>
> >+#endif
> >+
> >+void test01() {
> >+  typedef std::string_view::size_type csize_type;
> >+  typedef std::string_view::const_reference cref;
> >+  typedef std::string_view::reference ref;
> >+  csize_type csz01;
> >+
> >+  const char str_lit01[] = "rockaway, pacifica";
> >+  const std::string_view str01(str_lit01);
> >+  std::string_view str02;
> >+
> >+  csz01 = str01.size();
> >+  str02 = str01.subview(0, 1);
> >+  VERIFY(str02 == "r");
> >+  str02 = str01.subview(10);
> >+  VERIFY(str02 == "pacifica");
> >+
> >+#if __STDC_HOSTED__
> >+  try {
> >+    str02 = str01.subview(csz01 + 1);
> >+    VERIFY(false);
> >+  } catch (std::out_of_range &fail) {
> >+    VERIFY(true);
> >+  } catch (...) {
> >+    VERIFY(false);
> >+  }
> >+
> >+  try {
> >+    str02 = str01.subview(csz01);
> >+    VERIFY(str02.size() == 0);
> >+    VERIFY(str02.begin() == str01.end());
> >+    VERIFY(true);
> >+  } catch (...) {
> >+    VERIFY(false);
> >+  }
> >+#endif // HOSTED
> >+}
> >+
> >+int main() {
> >+  test01();
> >+
> >+  return 0;
> >+}
> >diff --git
> a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
> b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
> >new file mode 100644
> >index 00000000000..86b50959b5c
> >--- /dev/null
> >+++
> b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
> >@@ -0,0 +1,51 @@
> >+// { dg-do run { target c++26 } }
> >+
> >+#include <string_view>
> >+#include <testsuite_hooks.h>
> >+
> >+#if __STDC_HOSTED__
> >+#include <stdexcept>
> >+#endif
> >+
> >+void test01() {
> >+  typedef std::wstring_view::size_type csize_type;
> >+  typedef std::wstring_view::const_reference cref;
> >+  typedef std::wstring_view::reference ref;
> >+  csize_type csz01;
> >+
> >+  const wchar_t str_lit01[] = L"rockaway, pacifica";
> >+  const std::wstring_view str01(str_lit01);
> >+  std::wstring_view str02;
> >+
> >+  csz01 = str01.size();
> >+  str02 = str01.subview(0, 1);
> >+  VERIFY(str02 == L"r");
> >+  str02 = str01.subview(10);
> >+  VERIFY(str02 == L"pacifica");
> >+
> >+#if __STDC_HOSTED__
> >+  try {
> >+    str02 = str01.subview(csz01 + 1);
> >+    VERIFY(false);
> >+  } catch (std::out_of_range &fail) {
> >+    VERIFY(true);
> >+  } catch (...) {
> >+    VERIFY(false);
> >+  }
> >+
> >+  try {
> >+    str02 = str01.subview(csz01);
> >+    VERIFY(str02.size() == 0);
> >+    VERIFY(str02.begin() == str01.end());
> >+    VERIFY(true);
> >+  } catch (...) {
> >+    VERIFY(false);
> >+  }
> >+#endif // HOSTED
> >+}
> >+
> >+int main() {
> >+  test01();
> >+
> >+  return 0;
> >+}
> >--
> >2.51.1
> >
>
>

Reply via email to