On Tue, Dec 2, 2025 at 11:22 PM Jonathan Wakely <[email protected]> wrote:
>
> On Tue, 2 Dec 2025 at 15:09, Yuao Ma <[email protected]> wrote:
> >
> > Hi Patrick,
> >
> > On Tue, Dec 2, 2025 at 3:27 AM Patrick Palka <[email protected]> wrote:
> > >
> > > On Sat, 22 Nov 2025, Yuao Ma wrote:
> > >
> > > > On Sat, Nov 22, 2025 at 12:33 AM Tomasz Kaminski <[email protected]> 
> > > > wrote:
> > > > >
> > > > >
> > > > >
> > > > > On Fri, Nov 21, 2025 at 5:11 PM Yuao Ma <[email protected]> wrote:
> > > > >>
> > > > >> On Fri, Nov 21, 2025 at 6:32 PM Tomasz Kaminski 
> > > > >> <[email protected]> wrote:
> > > > >> >
> > > > >> > 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
> > > > >> >
> > > > >>
> > > > >> Thanks for the info! Could you elaborate more on how making this a
> > > > >> patch series helps with reverting? My understanding of P3862R0 is 
> > > > >> that
> > > > >> it proposed two wording options: one to entirely remove the subview
> > > > >> for string and string_view, and the other to remove the default
> > > > >> parameter argument.
> > > > >
> > > > > Both wording options are changing only basic_string::subview,
> > > > >  and not touching subview on string_view at all.
> > > >
> > > > Oh yeah, my mistake. Split into two patches as below.
> > >
> > > > From 668363e4dbf6db6d7cd40899a480256936dcd0ae Mon Sep 17 00:00:00 2001
> > > > From: Yuao Ma <[email protected]>
> > > > Date: Sat, 22 Nov 2025 00:37:48 +0800
> > > > Subject: [PATCH 1/2] libstdc++: implement P3044R2 - sub-string_view from
> > > >  string (string_view part)
> > > >
> > > > libstdc++-v3/ChangeLog:
> > > >
> > > >       * include/bits/version.def: Add string_subview FTM.
> > > >       * include/bits/version.h: Regenerate.
> > > >       * include/std/string_view: Add subview.
> > > >       * 
> > > > 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/version.def         |  9 ++++
> > > >  libstdc++-v3/include/bits/version.h           | 10 ++++
> > > >  libstdc++-v3/include/std/string_view          | 10 +++-
> > > >  .../operations/subview/char.cc                | 52 +++++++++++++++++++
> > > >  .../operations/subview/wchar_t.cc             | 52 +++++++++++++++++++
> > > >  5 files changed, 132 insertions(+), 1 deletion(-)
> > > >  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/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;
> > >
> > > I think we need to add cxx11abi = yes if we don't support this with the
> > > COW string.  Wouldn't adding COW string support amount to a few extra
> > > lines in cow_string.h though?
> > >
> >
> > Yes I added cxx11abi = yes in the latest version of the patch:
> > https://gcc.gnu.org/pipermail/libstdc++/2025-November/064522.html
>
> Why not just support it for the old ABI though?
>
> Making it cxx11abi=yes means that basic_string_view::subview is not
> available, and that makes no sense.
>

Fixed.

> >
> > > > +  };
> > > > +};
> > > > +
> > > >  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_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
> > >
> > > IIUC since subview is specified as freestanding-deleted, we need to
> > > define it as deleted if we don't support it in freestanding mode.
> > > So perhaps why don't we just always define it in C++26 mode regardless
> > > of whether the FTM is defined?  Maybe I'm not understanding the
> > > intent of freestanding-deleted though.
> > >
> >
> > IMHO __glibcxx_string_subview is guarded under HOSTED. Should I
> > explicitly mark this as deleted in freestanding mode?
>
> We should just support it for freestanding. It's only marked
> freestanding deleted because it might throw an exception, and in the
> standard everything that can throw an exception is not included in
> freestanding.  But we can just abort instead of throwing. We already
> support basic_string_view::substr, basic_string_view::compare etc.
>
> So I think we don't want the macro to depend on cxx11abi or on hosted.
> Then the basic_string_view::subview member will always be defined for
> C++26.
>

Fixed.

Please take another look, thanks!
From 235af51075eaf989c99409abbd6cb7d9f2e96017 Mon Sep 17 00:00:00 2001
From: Yuao Ma <[email protected]>
Date: Tue, 2 Dec 2025 23:35:40 +0800
Subject: [PATCH 2/2] libstdc++: implement P3044R2 - sub-string_view from
 string (string part) libstdc++-v3/ChangeLog:

        * include/bits/basic_string.h: Add subview.
        * include/bits/cow_string.h: Add subview.
        * include/std/string: Add FTM.
        * testsuite/21_strings/basic_string/operations/subview/char.cc: New 
test.
        * testsuite/21_strings/basic_string/operations/subview/wchar_t.cc: New 
test.
---
 libstdc++-v3/include/bits/basic_string.h      | 19 ++++++++
 libstdc++-v3/include/bits/cow_string.h        | 19 ++++++++
 libstdc++-v3/include/std/string               |  1 +
 .../basic_string/operations/subview/char.cc   | 46 +++++++++++++++++++
 .../operations/subview/wchar_t.cc             | 46 +++++++++++++++++++
 5 files changed, 131 insertions(+)
 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

diff --git a/libstdc++-v3/include/bits/basic_string.h 
b/libstdc++-v3/include/bits/basic_string.h
index c4b6b1064a9..b1db722402f 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 `__n` characters starting at
+       *  `__pos`.  If the string is too short, use the remainder of the
+       *  characters.  If `__pos` is beyond the end of the string, out_of_range
+       *  is thrown.
+      */
+      [[nodiscard]]
+      constexpr 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/cow_string.h 
b/libstdc++-v3/include/bits/cow_string.h
index f9df2be20be..e59897eef49 100644
--- a/libstdc++-v3/include/bits/cow_string.h
+++ b/libstdc++-v3/include/bits/cow_string.h
@@ -2919,6 +2919,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { 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 `__n` characters starting at
+       *  `__pos`.  If the string is too short, use the remainder of the
+       *  characters.  If `__pos` is beyond the end of the string, out_of_range
+       *  is thrown.
+      */
+      [[nodiscard]]
+      constexpr 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/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/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;
+}
-- 
2.52.0

From 03a2927e1880af667dbae29c4701fed261c0f317 Mon Sep 17 00:00:00 2001
From: Yuao Ma <[email protected]>
Date: Tue, 2 Dec 2025 23:32:36 +0800
Subject: [PATCH 1/2] libstdc++: implement P3044R2 - sub-string_view from
 string (string_view part)

libstdc++-v3/ChangeLog:

        * include/bits/version.def: Add string_subview FTM.
        * include/bits/version.h: Regenerate.
        * include/std/string_view: Add subview.
        * 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/version.def         |  8 +++
 libstdc++-v3/include/bits/version.h           | 10 ++++
 libstdc++-v3/include/std/string_view          | 10 +++-
 .../operations/subview/char.cc                | 51 +++++++++++++++++++
 .../operations/subview/wchar_t.cc             | 51 +++++++++++++++++++
 5 files changed, 129 insertions(+), 1 deletion(-)
 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/version.def 
b/libstdc++-v3/include/bits/version.def
index 1fde9eef9d3..d20e08519ca 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1945,6 +1945,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = string_subview;
+  values = {
+    v = 202506;
+    cxxmin = 26;
+  };
+};
+
 ftms = {
   name = to_underlying;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 2ebc48b234b..c75368d44c2 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2170,6 +2170,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)
+#  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_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_view/operations/subview/char.cc
 
b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
new file mode 100644
index 00000000000..d6b66e6f732
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.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::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.52.0

Reply via email to