diff --git a/stl/inc/ranges b/stl/inc/ranges index eda6d3e0b1..dd9b4001e8 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -1903,20 +1903,22 @@ namespace ranges { template class _Sentinel; - template + template struct _Category_base {}; - template - struct _Category_base<_Base> { - using iterator_category = - conditional_t>>, - conditional_t>, contiguous_iterator_tag>, - random_access_iterator_tag, _Iter_cat_t>>, - input_iterator_tag>; + template + requires forward_range<_Maybe_const<_Const, _Vw>> + struct _Category_base<_Const> { + using _Base = _Maybe_const<_Const, _Vw>; + using iterator_category = conditional_t< + is_lvalue_reference_v&, range_reference_t<_Base>>>, + 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<_Const> { private: template friend class _Iterator; @@ -1946,8 +1948,8 @@ namespace ranges { using iterator_concept = conditional_t, random_access_iterator_tag, conditional_t, bidirectional_iterator_tag, conditional_t, forward_iterator_tag, input_iterator_tag>>>; - using value_type = remove_cvref_t>>; - using difference_type = range_difference_t<_Base>; + using value_type = remove_cvref_t&, range_reference_t<_Base>>>; + using difference_type = range_difference_t<_Base>; // clang-format off _Iterator() requires default_initializable> = default; diff --git a/tests/std/tests/P0896R4_views_transform/test.cpp b/tests/std/tests/P0896R4_views_transform/test.cpp index ba728f142f..c3e469f94e 100644 --- a/tests/std/tests/P0896R4_views_transform/test.cpp +++ b/tests/std/tests/P0896R4_views_transform/test.cpp @@ -321,6 +321,50 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { return true; } +// Test a function object whose const and non-const versions behave differently +struct difference_teller { + constexpr auto& operator()(auto&& x) noexcept { + auto& ref = x; + return ref; + } + + constexpr auto operator()(auto&& x) const noexcept { + return type_identity{}; + } +}; + +template +constexpr void test_difference_on_const_functor(Rng&& rng) { + using ranges::transform_view, ranges::input_range, ranges::forward_range, ranges::bidirectional_range, + ranges::random_access_range, ranges::iterator_t, ranges::range_reference_t, ranges::range_value_t; + + using V = views::all_t; + using TV = transform_view; + + auto r = forward(rng) | views::transform(difference_teller{}); + STATIC_ASSERT(is_same_v); + + STATIC_ASSERT(is_lvalue_reference_v>); + if constexpr (input_range) { + STATIC_ASSERT(is_object_v>); + STATIC_ASSERT(!is_same_v, range_value_t>); + } + + if constexpr (forward_range) { + using It = iterator_t; + using TVIt = iterator_t; + using VItCat = typename iterator_traits::iterator_category; + using TVItCat = typename iterator_traits::iterator_category; + STATIC_ASSERT( + is_same_v // + || (is_same_v && is_same_v) ); + } + + if constexpr (forward_range) { + STATIC_ASSERT(is_same_v>::iterator_category, input_iterator_tag>); + } +} + static constexpr int some_ints[] = {0, 1, 2, 3, 4, 5, 6, 7}; static constexpr int transformed_ints[] = {8, 9, 10, 11, 12, 13, 14, 15}; @@ -329,6 +373,9 @@ struct instantiator { static constexpr void call() { R r{some_ints}; test_one(r, transformed_ints); + + R r2{some_ints}; + test_difference_on_const_functor(r2); } };