This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of LEWG status.
join_view should be sized_range when applied to ranges of simd::vecSection: 25.7.14.2 [range.join.view], 25.7.15.2 [range.join.with.view], 25.7.16.2 [range.lazy.split.view] Status: LEWG Submitter: Hewill Kang Opened: 2025-10-02 Last modified: 2025-10-23
Priority: 3
View other active issues in [range.join.view].
View all other issues in [range.join.view].
View all issues with LEWG status.
Discussion:
Consider:
Collecting asimd::vec into a vector for output is a common use case. P3480R6
makes simd::vec a range so we can simply flatten it with views::join (original example from
the paper):
std::vector<std::simd::vec<float>> data; auto range_of_float = data | std::views::join;
In this case, it makes sense for join_view to be sized_range because simd::vec::size()
is a constant expression that can be multiplied by the original vector size to get the
result size of the join_view.
<ranges>, we use the tiny-range concept
to consider types that can obtain static sizes specifically, and simd::vec
seems to be a good fit.
[2025-10-23; Reflector poll; Status changed: New → LEWG and P3.]
Introducting statically sized ranges and handling them in views, should be handle as a paper.
The proposed change is also relevant to fixed-size span.
Proposed resolution:
This wording is relative to N5014.
Modify 25.7.14.2 [range.join.view] as indicated:
[Drafting note: The proposed wording follows the
tiny-range's way to check ifR::size()is a constant expression instead of further checkingranges::size(r)for simplicity.]
namespace std::ranges {
template<auto> struct require-constant; // exposition only
template<class R>
concept static-sized-range = // exposition only
sized_range<R> &&
requires { typename require-constant<remove_reference_t<R>::size()>; };
template<input_range V>
requires view<V> && input_range<range_reference_t<V>>>
class join_view : public view_interface<join_view<V>> {
[…]
public:
[…]
constexpr auto size()
requires sized_range<V> && static-sized-range<InnerRng> {
using CT = common_type_t<range_size_t<V>, range_size_t<InnerRng>>;
return CT(ranges::size(base_)) * CT(remove_reference_t<InnerRng>::size());
}
constexpr auto size() const
requires sized_range<const V> &&
static-sized-range<range_reference_t<const V>> {
using InnerConstRng = range_reference_t<const V>;
using CT = common_type_t<range_size_t<V>, range_size_t<InnerConstRng>>;
return CT(ranges::size(base_)) * CT(remove_reference_t<InnerConstRng>::size());
}
};
[…]
}
Modify 25.7.15.2 [range.join.with.view] as indicated:
namespace std::ranges {
[…]
template<input_range V, forward_range Pattern>
requires view<V> && input_range<range_reference_t<V>>
&& view<Pattern>
&& concatable<range_reference_t<V>, Pattern>
class join_with_view : public view_interface<join_with_view<V, Pattern>> {
[…]
public:
[…]
constexpr auto size()
requires sized_range<V> && sized_range<Pattern> &&
static-sized-range<InnerRng> {
using CT = common_type_t<
range_size_t<V>, range_size_t<InnerRng>, range_size_t<Pattern>>;
const auto base_size = ranges::size(base_);
if (base_size == 0)
return CT(0);
return CT(base_size) * CT(remove_reference_t<InnerRng>::size()) +
CT(base_size - 1) * CT(ranges::size(pattern_));
}
constexpr auto size() const
requires sized_range<const V> && sized_range<const Pattern> &&
static-sized-range<range_reference_t<const V>> {
using InnerConstRng = range_reference_t<const V>;
using CT = common_type_t<
range_size_t<const V>, range_size_t<InnerConstRng>, range_size_t<const Pattern>>;
const auto base_size = ranges::size(base_);
if (base_size == 0)
return CT(0);
return CT(base_size) * CT(remove_reference_t<InnerConstRng>::size()) +
CT(base_size - 1) * CT(ranges::size(pattern_));
}
};
[…]
}
Modify 25.7.16.2 [range.lazy.split.view] as indicated:
namespace std::ranges {
template<auto> struct require-constant; // exposition only
template<class R>
concept tiny-range = // exposition only
static-sized-range<R>sized_range<R> &&
requires { typename require-constant<remove_reference_t<R>::size()>; } &&
(remove_reference_t<R>::size() <= 1);
[…]
}