[PATCH v1] libstdc++: Better CTAD for span and mdspan [P3029].
Luc Grosheintz
luc.grosheintz@gmail.com
Fri Jul 4 08:33:28 GMT 2025
This implements P3029R1. In P3029R1, the CTAD for span is refined to
permit deducing the extent of the span from an integral constant, e.g.
span((T*) ptr, integral_constant<size_t, 5>{});
is deduced as span<T, 5>. Similarly, in
auto exts = extents(integral_constant<int, 2>);
auto md = mdspan((T*) ptr, integral_constant<int, 2>);
exts and md have types extents<size_t, 2> and mdspan<double,
extents<size_t, 2>>, respectively.
libstdc++-v3/ChangeLog:
* include/std/span (span): Update CTAD to enable
integral constants [P3029R1].
* include/std/mdspan (extents): ditto.
(mdspan): ditto.
* testsuite/23_containers/span/p3029.cc: New test.
* testsuite/23_containers/mdspan/p3029.cc: New test.
Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
---
libstdc++-v3/include/std/mdspan | 4 +-
libstdc++-v3/include/std/span | 20 ++++++-
.../testsuite/23_containers/mdspan/p3029.cc | 58 +++++++++++++++++++
.../testsuite/23_containers/span/p3029.cc | 11 ++++
4 files changed, 90 insertions(+), 3 deletions(-)
create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/p3029.cc
create mode 100644 libstdc++-v3/testsuite/23_containers/span/p3029.cc
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index f64804e2a42..51abf9624e0 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -419,7 +419,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Integrals>
requires (is_convertible_v<_Integrals, size_t> && ...)
explicit extents(_Integrals...) ->
- extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>;
+ extents<size_t, __detail::__maybe_static_ext<_Integrals>...>;
struct layout_left
{
@@ -1315,7 +1315,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& (sizeof...(_Integrals) > 0)
explicit mdspan(_ElementType*, _Integrals...)
-> mdspan<_ElementType,
- extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>>;
+ extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>;
template<typename _ElementType, typename _OIndexType, size_t _Nm>
mdspan(_ElementType*, span<_OIndexType, _Nm>)
diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span
index 49ab9109d83..5629a71b9bd 100644
--- a/libstdc++-v3/include/std/span
+++ b/libstdc++-v3/include/std/span
@@ -476,6 +476,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
};
// deduction guides
+ namespace __detail
+ {
+ template<typename _Tp>
+ concept __integral_constant_like = is_integral_v<decltype(_Tp::value)>
+ && !is_same_v<bool, remove_const_t<decltype(_Tp::value)>>
+ && convertible_to<_Tp, decltype(_Tp::value)>
+ && equality_comparable_with<_Tp, decltype(_Tp::value)>
+ && bool_constant<_Tp() == _Tp::value>::value
+ && bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value>
+ ::value;
+
+ template<typename _Tp>
+ constexpr size_t __maybe_static_ext = dynamic_extent;
+
+ template<__integral_constant_like _Tp>
+ constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value};
+ }
template<typename _Type, size_t _ArrayExtent>
span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>;
@@ -489,7 +506,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<contiguous_iterator _Iter, typename _End>
span(_Iter, _End)
- -> span<remove_reference_t<iter_reference_t<_Iter>>>;
+ -> span<remove_reference_t<iter_reference_t<_Iter>>,
+ __detail::__maybe_static_ext<_End>>;
template<ranges::contiguous_range _Range>
span(_Range &&)
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/p3029.cc b/libstdc++-v3/testsuite/23_containers/mdspan/p3029.cc
new file mode 100644
index 00000000000..7c38dc00bf4
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/p3029.cc
@@ -0,0 +1,58 @@
+// { dg-do run { target c++23 } }
+
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+constexpr bool
+test_extents()
+{
+ auto verify = [](auto actual, auto expected)
+ {
+ static_assert(std::same_as<decltype(actual), decltype(expected)>);
+ VERIFY(actual == expected);
+ };
+
+ constexpr auto c1 = std::integral_constant<size_t, 1>{};
+ constexpr auto c2 = std::integral_constant<int, 2>{};
+
+ verify(std::extents(1), std::extents<size_t, dyn>{1});
+ verify(std::extents(c1), std::extents<size_t, 1>{});
+ verify(std::extents(c2), std::extents<size_t, 2>{});
+ verify(std::extents(c1, 2), std::extents<size_t, 1, dyn>{2});
+ return true;
+}
+
+constexpr bool
+test_mdspan()
+{
+ std::array<double, 6> buffer{};
+ double * ptr = buffer.data();
+
+ auto verify = [ptr](auto actual, auto exts)
+ {
+ auto expected = std::mdspan<double, decltype(exts)>(ptr, exts);
+ static_assert(std::same_as<decltype(actual), decltype(expected)>);
+ VERIFY(actual.extents() == expected.extents());
+ };
+
+ auto c3 = std::integral_constant<int, 3>{};
+ auto c6 = std::integral_constant<int, 6>{};
+
+ verify(std::mdspan(ptr, 6), std::extents(6));
+ verify(std::mdspan(ptr, c6), std::extents(c6));
+ verify(std::mdspan(ptr, 2, c3), std::extents(2, c3));
+ return true;
+}
+
+int
+main()
+{
+ test_extents();
+ static_assert(test_extents());
+
+ test_mdspan();
+ static_assert(test_mdspan());
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/p3029.cc b/libstdc++-v3/testsuite/23_containers/span/p3029.cc
new file mode 100644
index 00000000000..e894255546f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/p3029.cc
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++20 } }
+
+#include <span>
+
+constexpr void
+test_ctad()
+{
+ std::array<double, 5> a{};
+ std::span s(a.data(), std::integral_constant<size_t, 5>{});
+ static_assert(std::same_as<decltype(s), std::span<double, 5>>);
+}
--
2.49.0
More information about the Libstdc++
mailing list