LWG-3448 transform_view's sentinel<false> not comparable with iterator<true> (#1458)

Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
Co-authored-by: Casey Carter <cartec69@gmail.com>
This commit is contained in:
Michael Schellenberger Costa 2020-12-04 00:14:00 +01:00 коммит произвёл GitHub
Родитель 2aa944beba
Коммит 8516f91a7a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 90 добавлений и 34 удалений

Просмотреть файл

@ -1426,26 +1426,19 @@ namespace ranges {
using _Parent_t = _Maybe_const<_Const, transform_view>;
using _Base = _Maybe_const<_Const, _Vw>;
template <bool _OtherConst>
using _Maybe_const_iter = iterator_t<_Maybe_const<_OtherConst, _Vw>>;
sentinel_t<_Base> _Last{};
_NODISCARD constexpr bool _Equal(const _Iterator<_Const>& _It) const
noexcept(noexcept(_It._Current == _Last)) {
template <bool _OtherConst>
_NODISCARD static constexpr const _Maybe_const_iter<_OtherConst>& _Get_current(
const _Iterator<_OtherConst>& _It) noexcept {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(
_It._Parent != nullptr, "cannot compare transform_view sentinel with value-initialized iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _It._Current == _Last;
}
_NODISCARD constexpr range_difference_t<_Base> _Distance_to(const _Iterator<_Const>& _It) const
noexcept(noexcept(_It._Current - _Last)) {
_STL_INTERNAL_STATIC_ASSERT(sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>);
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(
_It._Parent != nullptr, "cannot compare transform_view sentinel with value-initialized iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _It._Current - _Last;
return _It._Current;
}
public:
@ -1466,22 +1459,30 @@ namespace ranges {
return _Last;
}
_NODISCARD friend constexpr bool operator==(const _Iterator<_Const>& _Left,
const _Sentinel& _Right) noexcept(noexcept(_Right._Equal(_Left))) /* strengthened */ {
return _Right._Equal(_Left);
// clang-format off
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left,
const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) == _Right._Last)) /* strengthened */ {
return _Get_current(_Left) == _Right._Last;
}
_NODISCARD friend constexpr range_difference_t<_Base>
operator-(const _Iterator<_Const>& _Left, const _Sentinel& _Right) noexcept(
noexcept(_Right._Distance_to(
_Left))) /* strengthened */ requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> {
return _Right._Distance_to(_Left);
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>>
operator-(const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(
noexcept(_Get_current(_Left) - _Right._Last)) /* strengthened */ {
return _Get_current(_Left) - _Right._Last;
}
_NODISCARD friend constexpr range_difference_t<_Base>
operator-(const _Sentinel& _Left, const _Iterator<_Const>& _Right) noexcept(noexcept(_Left._Distance_to(
_Right))) /* strengthened */ requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> {
return -_Left._Distance_to(_Right);
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>>
operator-(const _Sentinel& _Left, const _Iterator<_OtherConst>& _Right) noexcept(
noexcept(_Left._Last - _Get_current(_Right))) /* strengthened */ {
return _Left._Last - _Get_current(_Right);
}
// clang-format on
};
public:
@ -2836,11 +2837,13 @@ namespace ranges {
friend class _Sentinel;
using _Base = _Maybe_const<_Const, _Vw>;
template <bool _OtherConst>
using _Maybe_const_iter = iterator_t<_Maybe_const<_OtherConst, _Vw>>;
sentinel_t<_Base> _Last{};
template <bool _OtherConst>
_NODISCARD static constexpr const iterator_t<_Maybe_const<_OtherConst, _Vw>>& _Get_current(
_NODISCARD static constexpr const _Maybe_const_iter<_OtherConst>& _Get_current(
const _Iterator<_OtherConst>& _It) noexcept {
return _It._Current;
}
@ -2865,7 +2868,7 @@ namespace ranges {
// clang-format off
template <bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
requires sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left,
const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) == _Right._Last)) /* strengthened */ {
// clang-format on
@ -2874,7 +2877,7 @@ namespace ranges {
// clang-format off
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
requires sized_sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(
noexcept(_Get_current(_Left) - _Right._Last)) /* strengthened */ {
@ -2884,7 +2887,7 @@ namespace ranges {
// clang-format off
template <bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
requires sized_sentinel_for<sentinel_t<_Base>, _Maybe_const_iter<_OtherConst>>
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
const _Sentinel& _Left, const _Iterator<_OtherConst>& _Right) noexcept(
noexcept(_Left._Last - _Get_current(_Right))) /* strengthened */ {

Просмотреть файл

@ -241,17 +241,27 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
STATIC_ASSERT(CanMemberEnd<R>);
STATIC_ASSERT(CanEnd<const R&> == (range<const V> && const_invocable));
if (!is_empty) {
same_as<sentinel_t<R>> auto i = r.end();
same_as<sentinel_t<R>> auto s = r.end();
static_assert(is_same_v<sentinel_t<R>, iterator_t<R>> == common_range<V>);
if constexpr (bidirectional_range<R> && common_range<R>) {
assert(*prev(i) == *prev(end(expected)));
assert(*prev(s) == *prev(end(expected)));
}
if constexpr (CanEnd<const R&>) {
same_as<sentinel_t<const R>> auto i2 = as_const(r).end();
same_as<sentinel_t<const R>> auto sc = as_const(r).end();
static_assert(is_same_v<sentinel_t<const R>, iterator_t<const R>> == common_range<const V>);
if constexpr (bidirectional_range<const R> && common_range<const R>) {
assert(*prev(i2) == *prev(end(expected)));
assert(*prev(sc) == *prev(end(expected)));
}
if (forward_range<V>) { // intentionally not if constexpr
// Compare with const / non-const iterators
const same_as<iterator_t<R>> auto i = r.begin();
const same_as<iterator_t<const R>> auto ic = as_const(r).begin();
assert(s != i);
assert(s != ic);
assert(sc != i);
assert(sc != ic);
}
}
}
@ -574,27 +584,55 @@ struct iterator_instantiator {
const auto first = r.begin();
const auto last = r.end();
const auto const_first = ranges::iterator_t<const R>{first};
const auto const_last = ranges::sentinel_t<const R>{last};
assert(first == first);
assert(I{} == I{});
STATIC_ASSERT(noexcept(first == first));
assert(first == const_first);
STATIC_ASSERT(noexcept(first == const_first));
assert(const_first == first);
STATIC_ASSERT(noexcept(const_first == first));
assert(!(first == last));
STATIC_ASSERT(noexcept(first == last));
assert(!(last == first));
STATIC_ASSERT(noexcept(last == first));
assert(!(const_first == last));
STATIC_ASSERT(noexcept(const_first == last));
assert(!(last == const_first));
STATIC_ASSERT(noexcept(last == const_first));
assert(!(first == const_last));
STATIC_ASSERT(noexcept(first == const_last));
assert(!(const_last == first));
STATIC_ASSERT(noexcept(const_last == first));
assert(!(first != first));
assert(!(I{} != I{}));
STATIC_ASSERT(noexcept(first != first));
if constexpr (forward_iterator<Iter>) {
const auto final = ranges::next(first, last);
const auto final = ranges::next(first, last);
const auto const_final = ranges::next(const_first, const_last);
assert(!(first == final));
assert(first != final);
assert(last == final);
assert(final == last);
assert(const_last == final);
assert(final == const_last);
assert(last == const_final);
assert(const_final == last);
assert(const_last == const_final);
assert(const_final == const_last);
assert(!(last != final));
assert(!(final != last));
@ -611,6 +649,21 @@ struct iterator_instantiator {
assert(first - last == -ranges::ssize(mutable_ints));
STATIC_ASSERT(noexcept(last - first));
STATIC_ASSERT(noexcept(first - last));
assert(last - const_first == ranges::ssize(mutable_ints));
assert(const_first - last == -ranges::ssize(mutable_ints));
STATIC_ASSERT(noexcept(last - const_first));
STATIC_ASSERT(noexcept(const_first - last));
assert(const_last - first == ranges::ssize(mutable_ints));
assert(first - const_last == -ranges::ssize(mutable_ints));
STATIC_ASSERT(noexcept(const_last - first));
STATIC_ASSERT(noexcept(first - const_last));
assert(const_last - const_first == ranges::ssize(mutable_ints));
assert(const_first - const_last == -ranges::ssize(mutable_ints));
STATIC_ASSERT(noexcept(const_last - const_first));
STATIC_ASSERT(noexcept(const_first - const_last));
}
if constexpr (random_access_iterator<Iter>) { // Validate relational operators