This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Tentatively NAD status.
span(R&&) CTAD apply P2280?Section: 23.7.2.2.3 [span.deduct] Status: Tentatively NAD Submitter: Hewill Kang Opened: 2025-10-04 Last modified: 2025-10-20
Priority: Not Prioritized
View all issues with Tentatively NAD status.
Discussion:
Thanks to P2280R4, simd::basic_vec's CTAD can specify template parameters
directly through ranges::size:
basic_vec(R&& r, ...) -> vec<ranges::range_value_t<R>, ranges::size(r)>
However, span with similar CTAD forms do not have this automatic static size optimization applied:
span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;
Do we need to do it for span?
span constructor actually requires R to be a contiguous_range and a
sized_range. If it is further required that ranges::size be a constant expression, only raw array,
array, span, ranges::empty_view, and ranges::single_view satisfy this requirement.
Given that span already has CTAD for raw arrays and arrays, this improvement is not
significant, but it still seems worthwhile as a compile-time optimization for certain
user-defined types or in some specialized cases (demo):
#include <array>
#include <ranges>
constexpr std::size_t N = 42;
auto to_span(auto& r) {
static_assert(std::ranges::size(r) == N); // ok after P2280
return std::span(r);
}
std::array<int, N> a;
auto s1 = to_span(a);
static_assert(std::same_as<decltype(s1), std::span<int, N>>);
auto r = std::array<int, N>{} | std::views::as_const; // as_const_view<owning_view<array<int, N>>>
auto s2 = to_span(r);
static_assert(std::same_as<decltype(s2), std::span<const int, N>>); // fire, ok after this PR
[2025-10-20 Reflector poll. Status changed: NAD → Tentatively NAD.]
This is breaking change, and we need a paper with analysis.
Proposed resolution:
This wording is relative to N5014.
Modify 23.7.2.2.1 [span.overview] as indicated:
namespace std {
template<class ElementType, size_t Extent = dynamic_extent>
class span {
[…]
};
[…]
template<class R>
span(R&& r) -> see belowspan<remove_reference_t<ranges::range_reference_t<R>>>;
}
Modify 23.7.2.2.3 [span.deduct] as indicated:
template<class R> span(R&& r) -> see belowspan<remove_reference_t<ranges::range_reference_t<R>>>;-2- Constraints:
-?- Remarks: LetRsatisfiesranges::contiguous_range.Tdenote the typeremove_reference_t<ranges::range_reference_t<R>>. The deduced type is equivalent to
(?.1) —
span<T, static_cast<size_t>(ranges::size(r))>ifRsatisfiesranges::sized_rangeandranges::size(r)is a constant expression.(?.2) —
span<T>otherwise.