diff --git a/stl/inc/iterator b/stl/inc/iterator index a9900a0eced..2705e290979 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -1016,15 +1016,20 @@ struct _Common_iterator_pointer_type<_Iter> { using pointer = decltype(_STD declval<_Iter&>().operator->()); }; +template +concept _Has_forward_category = requires { + typename _Iter_cat_t<_Iter>; + requires derived_from<_Iter_cat_t<_Iter>, forward_iterator_tag>; +}; + template struct iterator_traits> { - using iterator_concept = conditional_t, forward_iterator_tag, input_iterator_tag>; - using iterator_category = - conditional_t, forward_iterator_tag>, forward_iterator_tag, input_iterator_tag>; - using value_type = iter_value_t<_Iter>; - using difference_type = iter_difference_t<_Iter>; - using pointer = typename _Common_iterator_pointer_type<_Iter>::pointer; - using reference = iter_reference_t<_Iter>; + using iterator_concept = conditional_t, forward_iterator_tag, input_iterator_tag>; + using iterator_category = conditional_t<_Has_forward_category<_Iter>, forward_iterator_tag, input_iterator_tag>; + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + using pointer = typename _Common_iterator_pointer_type<_Iter>::pointer; + using reference = iter_reference_t<_Iter>; }; template diff --git a/stl/inc/ranges b/stl/inc/ranges index 8e5c0cde338..d4c9860429f 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -776,18 +776,36 @@ namespace ranges { { __j - __j } -> convertible_to<_Iota_diff_t<_Ty>>; }; + template + struct _Ioterator_category_base { + _NODISCARD auto operator<=>(const _Ioterator_category_base&) const = default; + }; + + template + struct _Ioterator_category_base<_Wi> { + using iterator_category = input_iterator_tag; + + _NODISCARD auto operator<=>(const _Ioterator_category_base&) const = default; + }; + template requires copyable<_Wi> - struct _Ioterator { + struct _Ioterator : _Ioterator_category_base<_Wi> { // clang-format on - /* [[no_unique_address]] */ _Wi _Current; + /* [[no_unique_address]] */ _Wi _Current{}; - using iterator_concept = conditional_t<_Advanceable<_Wi>, random_access_iterator_tag, + using iterator_concept = conditional_t<_Advanceable<_Wi>, random_access_iterator_tag, conditional_t<_Decrementable<_Wi>, bidirectional_iterator_tag, conditional_t, forward_iterator_tag, input_iterator_tag>>>; - using iterator_category = input_iterator_tag; - using value_type = _Wi; - using difference_type = _Iota_diff_t<_Wi>; + using value_type = _Wi; + using difference_type = _Iota_diff_t<_Wi>; + + // clang-format off + _Ioterator() requires default_initializable<_Wi> = default; + // clang-format on + + constexpr explicit _Ioterator(_Wi _Val) noexcept(is_nothrow_move_constructible_v<_Wi>) /* strengthened */ + : _Current(_STD move(_Val)) {} _NODISCARD constexpr _Wi operator*() const noexcept(is_nothrow_copy_constructible_v<_Wi>) { return _Current; @@ -914,13 +932,11 @@ namespace ranges { noexcept(!(_Left._Current < _Right._Current))) /* strengthened */ requires totally_ordered<_Wi> { return !(_Left._Current < _Right._Current); } + // clang-format off - _NODISCARD friend constexpr auto operator<=>(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( - noexcept(_Left._Current <=> _Right._Current)) /* strengthened */ - requires totally_ordered<_Wi> && three_way_comparable<_Wi> { - // clang-format on - return _Left._Current <=> _Right._Current; - } + _NODISCARD friend constexpr auto operator<=>(const _Ioterator& _Left, const _Ioterator& _Right) + requires totally_ordered<_Wi> && three_way_comparable<_Wi> = default; + // clang-format on _NODISCARD friend constexpr _Ioterator operator+(_Ioterator _It, const difference_type _Off) noexcept( noexcept(static_cast<_Wi>(_It._Current + _Off))) /* strengthened */ requires _Advanceable<_Wi> { @@ -1028,7 +1044,9 @@ namespace ranges { } _NODISCARD constexpr _Se end() const noexcept(is_nothrow_copy_constructible_v<_Bo>) /* strengthened */ { - if constexpr (same_as<_Bo, unreachable_sentinel_t>) { + if constexpr (same_as<_Wi, _Bo>) { + return _It{_Bound}; + } else if constexpr (same_as<_Bo, unreachable_sentinel_t>) { return unreachable_sentinel; } else { return _Se{_Bound}; @@ -1289,20 +1307,20 @@ namespace ranges { /* [[no_unique_address]] */ _Vw _Range{}; /* [[no_unique_address]] */ _Copyable_box<_Pr> _Pred{}; - template // TRANSITION, LWG-3289 + template struct _Category_base {}; // clang-format off - template <_Has_member_iterator_category _Traits> - struct _Category_base<_Traits> { + template + struct _Category_base<_View> { // clang-format on using iterator_category = - conditional_t, + conditional_t>, bidirectional_iterator_tag>, bidirectional_iterator_tag, - conditional_t, - forward_iterator_tag, input_iterator_tag>>; + conditional_t>, forward_iterator_tag>, + forward_iterator_tag, _Iter_cat_t>>>; }; - class _Iterator : public _Category_base>> { + class _Iterator : public _Category_base<_Vw> { private: /* [[no_unique_address]] */ iterator_t<_Vw> _Current{}; filter_view* _Parent{}; @@ -1574,21 +1592,21 @@ namespace ranges { template class _Sentinel; - template // TRANSITION, LWG-3289 + template struct _Category_base {}; // clang-format off - template <_Has_member_iterator_category _Traits, class _Base> - struct _Category_base<_Traits, _Base> { + template + struct _Category_base<_Base> { // clang-format on using iterator_category = conditional_t>>, - conditional_t, - random_access_iterator_tag, typename _Traits::iterator_category>, + conditional_t>, contiguous_iterator_tag>, + random_access_iterator_tag, _Iter_cat_t>>, input_iterator_tag>; }; template - class _Iterator : public _Category_base>, _Maybe_const<_Const, _Vw>> { + class _Iterator : public _Category_base<_Maybe_const<_Const, _Vw>> { private: template friend class _Iterator; @@ -2902,34 +2920,24 @@ namespace ranges { template class _Sentinel; - template // TRANSITION, LWG-3289 + template struct _Category_base {}; - // clang-format off - template - requires _Has_member_iterator_category<_OuterTraits> && _Has_member_iterator_category<_InnerTraits> - struct _Category_base<_OuterTraits, _InnerTraits, _Deref_is_glvalue, _Inner_common> { + template + struct _Category_base<_Outer, _Inner, true> { using iterator_category = - conditional_t<_Deref_is_glvalue && _Inner_common // per LWG issue unnumbered as of 2021-03-16 - && derived_from - && derived_from, + conditional_t // per LWG-3535 + && derived_from<_Iter_cat_t>, bidirectional_iterator_tag> // + && derived_from<_Iter_cat_t>, bidirectional_iterator_tag>, bidirectional_iterator_tag, - conditional_t<_Deref_is_glvalue - && derived_from - && derived_from, - forward_iterator_tag, - conditional_t - && derived_from, - input_iterator_tag, - output_iterator_tag>>>; + conditional_t>, forward_iterator_tag> // + && derived_from<_Iter_cat_t>, forward_iterator_tag>, + forward_iterator_tag, input_iterator_tag>>; }; - // clang-format on template - class _Iterator : public _Category_base>>, - iterator_traits>>, is_reference_v<_InnerRng<_Const>>, - common_range<_InnerRng<_Const>>> { + class _Iterator + : public _Category_base<_Maybe_const<_Const, _Vw>, _InnerRng<_Const>, is_reference_v<_InnerRng<_Const>>> { private: template friend class _Iterator; @@ -3284,10 +3292,8 @@ namespace ranges { template class _Outer_iter_base {}; - // clang-format off template class _Outer_iter_base<_Iter> { - // clang-format on protected: _Iter _Current{}; @@ -4002,18 +4008,20 @@ namespace ranges { template class _Sentinel; - template // TRANSITION, LWG-3289 + template struct _Category_base {}; - // clang-format off - template <_Has_member_iterator_category _Traits> - struct _Category_base<_Traits> { - // clang-format on - using iterator_category = typename _Traits::iterator_category; + template + struct _Category_base<_Base> { + using iterator_category = + conditional_t(*_STD declval>()))>, + input_iterator_tag, + conditional_t>, random_access_iterator_tag>, + random_access_iterator_tag, _Iter_cat_t>>>; }; template - class _Iterator : public _Category_base>> { + class _Iterator : public _Category_base<_Maybe_const<_Const, _Vw>> { private: template friend class _Iterator; diff --git a/stl/inc/xutility b/stl/inc/xutility index 6d3906aae83..9f4dcc4ba94 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -441,8 +441,8 @@ struct _Old_iter_traits_pointer { template <_Has_iter_types _It> struct _Iterator_traits_base<_It> { using iterator_category = typename _It::iterator_category; - using difference_type = typename _It::difference_type; using value_type = typename _It::value_type; + using difference_type = typename _It::difference_type; using pointer = typename _Old_iter_traits_pointer<_Has_member_pointer<_It>>::template _Apply<_It>; using reference = typename _It::reference; }; @@ -481,15 +481,12 @@ concept _Cpp17_input_iterator = _Cpp17_iterator<_It> }; template - requires (!_Has_iter_types<_It> && _Cpp17_iterator<_It> && !_Cpp17_input_iterator<_It> - // Implements the proposed resolution of LWG-3283: - && (!requires { typename _It::iterator_category; } - || derived_from)) + requires (!_Has_iter_types<_It> && _Cpp17_iterator<_It> && !_Cpp17_input_iterator<_It>) struct _Iterator_traits_base<_It> { using iterator_category = output_iterator_tag; + using value_type = void; using difference_type = typename _Iter_traits_difference<_Has_member_difference_type>>::template _Apply<_It>; - using value_type = void; using pointer = void; using reference = void; }; @@ -619,8 +616,8 @@ template requires (!_Has_iter_types<_It> && _Cpp17_input_iterator<_It>) struct _Iterator_traits_base<_It> { using iterator_category = typename _Iter_traits_category<_Has_member_iterator_category<_It>>::template _Apply<_It>; - using difference_type = typename incrementable_traits<_It>::difference_type; using value_type = typename indirectly_readable_traits<_It>::value_type; + using difference_type = typename incrementable_traits<_It>::difference_type; using pointer = typename _Iter_traits_pointer<( _Has_member_pointer<_It> ? _Itraits_pointer_strategy::_Use_member : _Has_member_arrow<_It&> ? _Itraits_pointer_strategy::_Use_decltype @@ -3551,24 +3548,36 @@ struct _Default_sentinel {}; // empty struct to serve as the end of a range #ifdef __cpp_lib_concepts template class move_sentinel; -#endif // __cpp_lib_concepts +template +struct _Move_iterator_category {}; + +// clang-format off template -class move_iterator { -public: - using iterator_type = _Iter; -#ifdef __cpp_lib_concepts - using iterator_concept = input_iterator_tag; + requires requires { typename _Iter_cat_t<_Iter>; } +struct _Move_iterator_category<_Iter> { using iterator_category = conditional_t, random_access_iterator_tag>, random_access_iterator_tag, _Iter_cat_t<_Iter>>; -#else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv +}; +// clang-format on +#else // ^^^ Ranges / no Ranges vvv +template +struct _Move_iterator_category { using iterator_category = _Iter_cat_t<_Iter>; +}; #endif // __cpp_lib_concepts + +template +class move_iterator : public _Move_iterator_category<_Iter> { +public: + using iterator_type = _Iter; using value_type = _Iter_value_t<_Iter>; using difference_type = _Iter_diff_t<_Iter>; using pointer = _Iter; + #ifdef __cpp_lib_concepts - using reference = iter_rvalue_reference_t<_Iter>; + using iterator_concept = input_iterator_tag; + using reference = iter_rvalue_reference_t<_Iter>; #else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv using reference = conditional_t>, remove_reference_t<_Iter_ref_t<_Iter>>&&, _Iter_ref_t<_Iter>>; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 84f1a357b7a..e3b95fb6ef3 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -247,7 +247,6 @@ // P2106R0 Range Algorithm Result Types // P2116R0 Removing tuple-Like Protocol Support From Fixed-Extent span // P2259R1 Repairing Input Range Adaptors And counted_iterator -// (partially implemented) // P2325R3 Views Should Not Be Required To Be Default Constructible // P????R? directory_entry::clear_cache() diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index a559d3b2d17..dad6843ab83 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -592,19 +592,36 @@ namespace test { } }; // clang-format on + + template + struct iterator_traits_base {}; + + template + struct iterator_traits_base { + using iterator_category = Category; + }; + + template + struct iterator_traits_base { + using iterator_category = input; + }; + + template + struct iterator_traits_base { + using iterator_category = input; + }; } // namespace test template -struct std::iterator_traits<::test::iterator> { - using iterator_concept = Category; - using iterator_category = conditional_t, // - conditional_t, // - conditional_t(Eq), Category, void>>; // TRANSITION, LWG-3289 - using value_type = remove_cv_t; - using difference_type = ptrdiff_t; - using pointer = conditional_t, Element*, void>; - using reference = iter_reference_t<::test::iterator>; +struct std::iterator_traits<::test::iterator> + : ::test::iterator_traits_base, + Proxy == ::test::ProxyRef::yes, Eq == ::test::CanCompare::yes> { + using iterator_concept = Category; + using value_type = remove_cv_t; + using difference_type = ptrdiff_t; + using pointer = conditional_t, Element*, void>; + using reference = iter_reference_t<::test::iterator>; }; template diff --git a/tests/std/tests/P0896R4_common_iterator/test.cpp b/tests/std/tests/P0896R4_common_iterator/test.cpp index 1c7b93b40ad..4736c7543aa 100644 --- a/tests/std/tests/P0896R4_common_iterator/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator/test.cpp @@ -194,6 +194,37 @@ bool test_operator_arrow() { return true; } +// common_iterator supports "copyable but not equality_comparable" iterators, which combination test::iterator does not +// provide (I don't think this is a combination of properties that any real iterator will ever exhibit). Whip up +// something so we can test the iterator_category metaprogramming. +// clang-format off +template +concept no_iterator_traits = !requires { typename iterator_traits::iterator_concept; } + && !requires { typename iterator_traits::iterator_category; } + && !requires { typename iterator_traits::value_type; } + && !requires { typename iterator_traits::difference_type; } + && !requires { typename iterator_traits::pointer; } + && !requires { typename iterator_traits::reference; }; +// clang-format on + +struct input_copy_but_no_eq { + using value_type = int; + using difference_type = int; + + input_copy_but_no_eq() = delete; + + int operator*() const; + input_copy_but_no_eq& operator++(); + void operator++(int); + + bool operator==(default_sentinel_t) const; +}; +STATIC_ASSERT(input_iterator); +STATIC_ASSERT(no_iterator_traits); +STATIC_ASSERT(sentinel_for); +using ICID = iterator_traits>; +STATIC_ASSERT(same_as); + int main() { with_writable_iterators::call(); diff --git a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp index 137e1e7952a..425dfe6dd18 100644 --- a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp @@ -1805,7 +1805,7 @@ namespace unreachable_sentinel_test { namespace unwrap_move_only { // Validate the iterator unwrapping machinery works with move-only iterators, and that move-only iterators are not - // C++17 iterators (per the proposed resolution of LWG-3283) + // C++17 iterators template struct iter { @@ -3082,11 +3082,10 @@ namespace move_iterator_test { template struct input_iter { - using iterator_concept = input_iterator_tag; - using iterator_category = void; - using value_type = int; - using difference_type = int; - using pointer = void; + using iterator_concept = input_iterator_tag; + using value_type = int; + using difference_type = int; + using pointer = void; struct reference { operator int() const; @@ -3164,6 +3163,8 @@ namespace move_iterator_test { STATIC_ASSERT(same_as>::iterator_category, forward_iterator_tag>); STATIC_ASSERT(same_as::iterator_concept, input_iterator_tag>); STATIC_ASSERT(same_as::iterator_category, input_iterator_tag>); + STATIC_ASSERT(!has_member_iter_category>>); + STATIC_ASSERT(!has_member_iter_category>>); // Validate that move_iterator::reference is iter_rvalue_reference_t STATIC_ASSERT(same_as>::reference, input_iter::rvalue_reference>); diff --git a/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp b/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp index 8bf8494afff..46c7dc3e4cc 100644 --- a/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp +++ b/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp @@ -1065,12 +1065,11 @@ namespace test_subrange { struct with_converting_iterators { template struct iterator { - using iterator_concept = input_iterator_tag; - using iterator_category = void; // TRANSITION, LWG-3289 - using value_type = int; - using difference_type = int; - using pointer = void; - using reference = int; + using iterator_concept = input_iterator_tag; + using value_type = int; + using difference_type = int; + using pointer = void; + using reference = int; iterator() = default; iterator(iterator) requires IsConst; diff --git a/tests/std/tests/P0896R4_views_filter_iterator/test.cpp b/tests/std/tests/P0896R4_views_filter_iterator/test.cpp index 7098949ada5..12f09a3c033 100644 --- a/tests/std/tests/P0896R4_views_filter_iterator/test.cpp +++ b/tests/std/tests/P0896R4_views_filter_iterator/test.cpp @@ -30,10 +30,13 @@ struct iterator_instantiator { conditional_t, bidirectional_iterator_tag, conditional_t, forward_iterator_tag, input_iterator_tag>>>); - using C = typename iterator_traits::iterator_category; - static_assert(is_same_v, bidirectional_iterator_tag, - conditional_t, forward_iterator_tag, input_iterator_tag>>>); + static_assert(_Has_member_iterator_category == forward_iterator); + if constexpr (forward_iterator) { + using C = typename iterator_traits::iterator_category; + static_assert(is_same_v, bidirectional_iterator_tag, + conditional_t, forward_iterator_tag, input_iterator_tag>>>); + } { // Validate iterator special member functions and base static_assert(default_initializable == default_initializable); diff --git a/tests/std/tests/P0896R4_views_transform/test.cpp b/tests/std/tests/P0896R4_views_transform/test.cpp index a7b116d4bba..7f1d108a9c9 100644 --- a/tests/std/tests/P0896R4_views_transform/test.cpp +++ b/tests/std/tests/P0896R4_views_transform/test.cpp @@ -429,11 +429,10 @@ struct iterator_instantiator { conditional_t, bidirectional_iterator_tag, conditional_t, forward_iterator_tag, input_iterator_tag>>>>); - using C = typename iterator_traits::iterator_category; - STATIC_ASSERT(is_same_v>>, - conditional_t, random_access_iterator_tag, C>, - input_iterator_tag>>); + STATIC_ASSERT(_Has_member_iterator_category == forward_iterator); + if constexpr (forward_iterator) { + STATIC_ASSERT(is_same_v); + } { // Validate iterator special member functions and base STATIC_ASSERT(default_initializable == default_initializable);