On 7/8/25 17:11, Tomasz Kaminski wrote:
This was merged. Thanks for working on it.
However, the constant_wrapper paper accepted in Sofia, modifies the concept:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2781r8.html
Interesting! I'll go hiking for 3 days, then I'll look at this and
write the test related to negative numbers.
Are you proposing implementing the whole of P2781 or just the mdspan
related change?
On Tue, Jul 8, 2025 at 1:01 PM Tomasz Kaminski <tkami...@redhat.com> wrote:
Maybe adding a negative test for the error when converting negative values
would be valuable then.
I think we can add it as separate commit later, I will try to get
everything merged today,
On Tue, Jul 8, 2025 at 12:56 PM Jonathan Wakely <jwak...@redhat.com>
wrote:
On Tue, 8 Jul 2025 at 11:46, Tomasz Kaminski <tkami...@redhat.com> wrote:
On Tue, Jul 8, 2025 at 12:08 PM Jonathan Wakely <jwak...@redhat.com>
wrote:
On Tue, 8 Jul 2025 at 10:54, Luc Grosheintz <luc.groshei...@gmail.com>
wrote:
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.
PR libstdc++/120914
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/deduction.cc: Test deduction
guide.
* testsuite/23_containers/mdspan/extents/misc.cc: ditto.
* testsuite/23_containers/mdspan/mdspan.cc: ditto.
Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
---
libstdc++-v3/include/std/mdspan | 8 ++----
libstdc++-v3/include/std/span | 20 ++++++++++++++-
.../23_containers/mdspan/extents/misc.cc | 20 +++++++++++++++
.../testsuite/23_containers/mdspan/mdspan.cc | 25
+++++++++++++++++++
.../testsuite/23_containers/span/deduction.cc | 3 +++
5 files changed, 69 insertions(+), 7 deletions(-)
diff --git a/libstdc++-v3/include/std/mdspan
b/libstdc++-v3/include/std/mdspan
index 0fd78570b3e..152dcb3e92a 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -406,10 +406,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _IndexType, size_t... _Counts>
auto __build_dextents_type(integer_sequence<size_t,
_Counts...>)
-> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
-
- template<typename _Tp>
- consteval size_t
- __dynamic_extent() { return dynamic_extent; }
}
template<typename _IndexType, size_t _Rank>
@@ -419,7 +415,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
{
@@ -1316,7 +1312,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};
Are the braces here to detect narrowing conversions?
(The paper doesn't mention why they're used, as far as I can see)
The information is in revision history (a bit hidden):
Initialized the maybe-static-ext's specialization with {T::value} to
prevent conversions from negative values.
Thanks. OK for trunk then.
+ }
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/extents/misc.cc
b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
index e71fdc54230..bca8901685d 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
@@ -97,6 +97,25 @@ test_deduction(Extents... exts)
VERIFY(e == expected);
}
+constexpr bool
+test_integral_constant_deduction()
+{
+ 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_deduction_all()
{
@@ -104,6 +123,7 @@ test_deduction_all()
test_deduction<1>(1);
test_deduction<2>(1.0, 2.0f);
test_deduction<3>(int(1), short(2), size_t(3));
+ test_integral_constant_deduction();
return true;
}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
index 9252273bf66..a650fb19bdf 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
@@ -245,6 +245,28 @@ test_from_pointer_and_shape()
return true;
}
+constexpr bool
+test_from_pointer_and_integral_constant()
+{
+ 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;
+}
+
constexpr bool
test_from_extents()
{
@@ -616,6 +638,9 @@ main()
test_from_pointer_and_shape();
static_assert(test_from_pointer_and_shape());
+ test_from_pointer_and_integral_constant();
+ static_assert(test_from_pointer_and_integral_constant());
+
test_from_extents();
static_assert(test_from_extents());
diff --git a/libstdc++-v3/testsuite/23_containers/span/deduction.cc
b/libstdc++-v3/testsuite/23_containers/span/deduction.cc
index dce6cedf89b..c66db90222e 100644
--- a/libstdc++-v3/testsuite/23_containers/span/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/span/deduction.cc
@@ -80,4 +80,7 @@ test01()
std::span s12(const_cast<const std::span<int>&>(s5));
static_assert( is_dynamic_span<int>(s12) );
+
+ std::span s13(a.data(), std::integral_constant<size_t, 3>{});
+ static_assert( is_static_span<long, 3>(s13));
}
--
2.49.0