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