Issue 4027: possibly-const-range should prefer returning const R& (original) (raw)
This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
4027. _possibly-const-range_
should prefer returning const R&
Section: 25.2 [ranges.syn] Status: WP Submitter: Hewill Kang Opened: 2023-12-17 Last modified: 2024-11-28
Priority: 2
View all other issues in [ranges.syn].
View all issues with WP status.
Discussion:
_possibly-const-range_
currently only returns const R&
when R
does not satisfy constant_range
and const R
satisfies constant_range
.
Although it's not clear why we need the former condition, this does diverge from the legacy std::cbegin
(demo):
#include
int main() { auto r = std::views::single(0) | std::views::transform( { return 0; }); using C1 = decltype(std::ranges::cbegin(r)); using C2 = decltype(std::cbegin(r)); static_assert(std::same_as<C1, C2>); // failed }
Since R
itself is constant_range
, so _possibly-const-range_
, above just returns R&
and C1
is transform_view::_iterator_<false>
; std::cbegin
specifies to return as_const(r).begin()
, which makes that C2
is transform_view::_iterator_<true>
which is different from C1
.
I believe const R&
should always be returned if it's a range, regardless of whether const R
or R
is a constant_range
, just as _fmt-maybe-const_
in format ranges always prefers const R
over R
.
Although it is theoretically possible for R
to satisfy constant_range
and that const R
is a mutable range, such nonsense range type should not be of interest.
This relaxation of constraints allows for maximum consistency with std::cbegin
, and in some cases can preserve constness to the greatest extent (demo):
#include
int main() { auto r = std::views::single(0) | std::views::lazy_split(0); (*std::ranges::cbegin(r)).front() = 42; // ok (*std::cbegin(r)).front() = 42; // not ok }
Above, *std::ranges::cbegin
returns a range of type const lazy_split_view::_outer-iterator_<false>::value_type
, which does not satisfy constant_range
because its reference type is int&
.
However, *std::cbegin(r)
returns lazy_split_view::_outer-iterator_<true>::value_type
whose reference type is const int&
and satisfies constant_range
.
[2024-03-11; Reflector poll]
Set priority to 2 after reflector poll. Send to SG9.
[St. Louis 2024-06-28; LWG and SG9 joint session: move to Ready]
[Wrocław 2024-11-23; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4971.
- Modify 25.2 [ranges.syn], header
<ranges>
synopsis, as indicated:#include // see 17.12.1 [compare.syn]
#include // see 17.11.2 [initializer.list.syn]
#include // see 24.2 [iterator.synopsis]namespace std::ranges {
[…]// 25.7.22 [range.as.const], as const view
template
constexpr auto& possibly-const-range(R& r) noexcept { // exposition only
if constexpr (inputconstant_range&& !constant_range) {
return const_cast<const R&>(r); } else { return r; }
}
[…]
}