This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
span(R&&)
CTAD apply P2280?Section: 23.7.2.2.3 [span.deduct] Status: New Submitter: Hewill Kang Opened: 2025-10-04 Last modified: 2025-10-05
Priority: Not Prioritized
View all issues with New 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 array
s, 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
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: LetR
satisfiesranges::contiguous_range
.T
denote 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))>
ifR
satisfiesranges::sized_range
andranges::size(r)
is a constant expression.(?.2) —
span<T>
otherwise.