[RFC v2 4/4] libstdc++: Support types decomposible in tree elements as range_slice equivalent.

Tomasz Kamiński tkaminsk@redhat.com
Fri Mar 20 07:54:00 GMT 2026


This was originally proposed P3982R0, and was dropped in R1 as extension
that can be added in C++29.

libstdc++-v3/ChangeLog:

	* include/bits/version.def (submdspan): Update to arbitrally
	selected 202600 value.
	* include/bits/version.h: Regenerate.
	* include/std/mdspan (__slice_cast): Handle types decomposing
	into two or tree elemenst.
	* testsuite/23_containers/mdspan/submdspan/canonical_slices.cc:
	Test tuple and user-defined 3 elements structure.
	* testsuite/23_containers/mdspan/submdspan/subextents.cc:
	Likewise.
---
 libstdc++-v3/include/bits/version.def          |  6 ++++++
 libstdc++-v3/include/bits/version.h            |  7 ++++++-
 libstdc++-v3/include/std/mdspan                | 18 ++++++++++++++++--
 .../mdspan/submdspan/canonical_slices.cc       | 10 ++++++++++
 .../mdspan/submdspan/subextents.cc             | 10 ++++++++++
 5 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index d1f39207107..09bc3a2d900 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1117,6 +1117,12 @@ ftms = {
 
 ftms = {
   name = submdspan;
+  values = {
+    v = 202600; // RFC Decompose tuple into tree elements
+    cxxmin = 26;
+    extra_cond = "__glibcxx_constant_wrapper >= 202506L"
+    "&& __cpp_structured_bindings >= 202411L";
+  };
   values = {
     v = 202503; // P3982R1 Split strided_slice into extent_slice and range_slice for C++26
     cxxmin = 26;
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 97fb82e0645..2f50389aed9 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1242,7 +1242,12 @@
 #undef __glibcxx_want_padded_layouts
 
 #if !defined(__cpp_lib_submdspan)
-# if (__cplusplus >  202302L) && (__glibcxx_constant_wrapper >= 202506L)
+# if (__cplusplus >  202302L) && (__glibcxx_constant_wrapper >= 202506L&& __cpp_structured_bindings >= 202411L)
+#  define __glibcxx_submdspan 202600L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_submdspan)
+#   define __cpp_lib_submdspan 202600L
+#  endif
+# elif (__cplusplus >  202302L) && (__glibcxx_constant_wrapper >= 202506L)
 #  define __glibcxx_submdspan 202503L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_submdspan)
 #   define __cpp_lib_submdspan 202503L
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index f30c5e83d16..d335b0a9aff 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -3365,15 +3365,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  }
 	else
 	  {
+#if __glibcxx_submdspan >= 202600L 
+	    auto [__sbegin, __send, ...__sstrides] = std::move(__slice);
+#else
 	    auto [__sbegin, __send] = std::move(__slice);
+#endif
+
 	    auto __cbegin
 	      = __mdspan::__canonical_index<_IndexType>(std::move(__sbegin));
 	    auto __cend
 	      = __mdspan::__canonical_index<_IndexType>(std::move(__send));
 	    auto __cspan
 	      = __mdspan::__canonical_index<_IndexType>(__cend - __cbegin);
-	    return __mdspan::__canonical_range_slice<_IndexType>(
-		     __cbegin, __cspan, cw<_IndexType(1)>);
+#if __glibcxx_submdspan >= 202600L 
+	    static_assert(sizeof...(__sstrides) <= 1u);
+	    if constexpr (sizeof...(__sstrides) > 0u)
+	      return __mdspan::__canonical_range_slice<_IndexType>(
+		__cbegin, __cspan,
+		__mdspan::__canonical_index<_IndexType>(std::move(__sstrides))...
+	      );
+	    else
+#endif
+	      return __mdspan::__canonical_range_slice<_IndexType>(
+		__cbegin, __cspan, cw<_IndexType(1)>);
 	  }
       }
 
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
index d747ad40de2..519e762e9fd 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
@@ -234,10 +234,20 @@ test_triple()
   return true;
 }
 
+template<typename Lower, typename Upper, typename Stride>
+struct StridedRange
+{
+  Lower lower;
+  Upper upper;
+  Stride stride;
+};
+
 constexpr bool
 test_triple_all()
 {
   test_triple<std::range_slice>();
+  test_triple<std::tuple>();
+  test_triple<StridedRange>();
   return true;
 }
 
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
index 35927a0276e..e168f47f3fb 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
@@ -226,11 +226,21 @@ template<template<typename, typename, typename> class Triple,
     return true;
   }
 
+template<typename Lower, typename Upper, typename Stride>
+struct StridedRange
+{
+  Lower lower;
+  Upper upper;
+  Stride stride;
+};
+
 template<template<int> typename Cw>
   constexpr bool
   test_from_triple_all()
   {
     test_from_triple<std::range_slice, Cw>();
+    test_from_triple<std::tuple, Cw>();
+    test_from_triple<StridedRange, Cw>();
     return true;
   }
 
-- 
2.53.0



More information about the Libstdc++ mailing list