libstdc++: Make range adaptor __has_arrow helper use a const type
LWG 4112 (approved in Wrocław, November 2024) changes the has-arrow helper to require operator-> to be valid on a const-qualified lvalue. This affects the constraints for filter_view::_Iterator::operator-> and join_view::_Iterator::operator-> so that they can only be used if the underlying iterator supports operator-> on const. The change also adds semantic (i.e. not checkable and not enforced) requirements that operator-> must have the same semantics whether called on a const or non-const value, and on an lvalue or rvalue (due to the implicit expression variation rules in [concepts.equality]). libstdc++-v3/ChangeLog: * include/bits/ranges_util.h (ranges::_detail::__has_arrow): Require operator->() to be valid on const-qualified type, as per LWG 4112. * testsuite/std/ranges/adaptors/lwg4112.cc: New test. Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
parent
a21847acb8
commit
04815ae0a2
2 changed files with 45 additions and 1 deletions
|
@ -54,9 +54,12 @@ namespace ranges
|
|||
&& same_as<iterator_t<_Range>, iterator_t<const _Range>>
|
||||
&& same_as<sentinel_t<_Range>, sentinel_t<const _Range>>;
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4112. has-arrow should required operator->() to be const-qualified
|
||||
template<typename _It>
|
||||
concept __has_arrow = input_iterator<_It>
|
||||
&& (is_pointer_v<_It> || requires(_It __it) { __it.operator->(); });
|
||||
&& (is_pointer_v<_It>
|
||||
|| requires(const _It __it) { __it.operator->(); });
|
||||
|
||||
using std::__detail::__different_from;
|
||||
} // namespace __detail
|
||||
|
|
41
libstdc++-v3/testsuite/std/ranges/adaptors/lwg4112.cc
Normal file
41
libstdc++-v3/testsuite/std/ranges/adaptors/lwg4112.cc
Normal file
|
@ -0,0 +1,41 @@
|
|||
// { dg-do compile { target c++20 } }
|
||||
|
||||
// LWG 4112. has-arrow should required operator->() to be const-qualified
|
||||
|
||||
// The issue resolution means that range adaptors which use has-arrow to
|
||||
// constrain their iterator's operator-> should require a const-qualified
|
||||
// operator-> on the underlying view's iterator.
|
||||
|
||||
#include <ranges>
|
||||
|
||||
struct Int { int i = 0; };
|
||||
|
||||
struct Iter
|
||||
{
|
||||
using value_type = Int;
|
||||
using difference_type = int;
|
||||
|
||||
mutable Int val;
|
||||
|
||||
Int& operator*() const { return val; }
|
||||
Int* operator->() /* non-const */ { return &val; }
|
||||
Iter& operator++() { ++val.i; return *this; }
|
||||
void operator++(int) { ++val.i; }
|
||||
bool operator==(const Iter& j) const { return val.i == j.val.i; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept has_op_arrow = requires (T t) { t.operator->(); };
|
||||
|
||||
static_assert( has_op_arrow<Iter> );
|
||||
static_assert( ! has_op_arrow<const Iter> );
|
||||
|
||||
using Range = std::ranges::subrange<Iter>;
|
||||
using Pred = bool(*)(Int);
|
||||
using FilterView = std::ranges::filter_view<Range, Pred>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
static_assert( ! has_op_arrow<FilterIterator> );
|
||||
static_assert( ! has_op_arrow<FilterIterator&> );
|
||||
static_assert( ! has_op_arrow<FilterIterator const> );
|
||||
static_assert( ! has_op_arrow<FilterIterator const&> );
|
Loading…
Add table
Reference in a new issue