Skip to content

Commit

Permalink
Implement LWG-3564: transform_view::iterator<true>::value_type and …
Browse files Browse the repository at this point in the history
…`iterator_category` should use `const F&` (microsoft#2961)
  • Loading branch information
frederick-vs-ja authored and fsb4000 committed Aug 13, 2022
1 parent aa5e60e commit ebafd4e
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 11 deletions.
24 changes: 13 additions & 11 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -1903,20 +1903,22 @@ namespace ranges {
template <bool _Const>
class _Sentinel;

template <class _Base>
template <bool _Const>
struct _Category_base {};

template <forward_range _Base>
struct _Category_base<_Base> {
using iterator_category =
conditional_t<is_lvalue_reference_v<invoke_result_t<_Fn&, range_reference_t<_Base>>>,
conditional_t<derived_from<_Iter_cat_t<iterator_t<_Base>>, contiguous_iterator_tag>,
random_access_iterator_tag, _Iter_cat_t<iterator_t<_Base>>>,
input_iterator_tag>;
template <bool _Const>
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<invoke_result_t<_Maybe_const<_Const, _Fn>&, range_reference_t<_Base>>>,
conditional_t<derived_from<_Iter_cat_t<iterator_t<_Base>>, contiguous_iterator_tag>,
random_access_iterator_tag, _Iter_cat_t<iterator_t<_Base>>>,
input_iterator_tag>;
};

template <bool _Const>
class _Iterator : public _Category_base<_Maybe_const<_Const, _Vw>> {
class _Iterator : public _Category_base<_Const> {
private:
template <bool>
friend class _Iterator;
Expand Down Expand Up @@ -1946,8 +1948,8 @@ namespace ranges {
using iterator_concept = conditional_t<random_access_range<_Base>, random_access_iterator_tag,
conditional_t<bidirectional_range<_Base>, bidirectional_iterator_tag,
conditional_t<forward_range<_Base>, forward_iterator_tag, input_iterator_tag>>>;
using value_type = remove_cvref_t<invoke_result_t<_Fn&, range_reference_t<_Base>>>;
using difference_type = range_difference_t<_Base>;
using value_type = remove_cvref_t<invoke_result_t<_Maybe_const<_Const, _Fn>&, range_reference_t<_Base>>>;
using difference_type = range_difference_t<_Base>;

// clang-format off
_Iterator() requires default_initializable<iterator_t<_Base>> = default;
Expand Down
47 changes: 47 additions & 0 deletions tests/std/tests/P0896R4_views_transform/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<decltype(x)>{};
}
};

template <ranges::input_range Rng>
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<Rng>;
using TV = transform_view<V, difference_teller>;

auto r = forward<Rng>(rng) | views::transform(difference_teller{});
STATIC_ASSERT(is_same_v<decltype(r), TV>);

STATIC_ASSERT(is_lvalue_reference_v<range_reference_t<TV>>);
if constexpr (input_range<const TV>) {
STATIC_ASSERT(is_object_v<range_reference_t<const TV>>);
STATIC_ASSERT(!is_same_v<range_value_t<TV>, range_value_t<const TV>>);
}

if constexpr (forward_range<V>) {
using It = iterator_t<V>;
using TVIt = iterator_t<TV>;
using VItCat = typename iterator_traits<It>::iterator_category;
using TVItCat = typename iterator_traits<TVIt>::iterator_category;
STATIC_ASSERT(
is_same_v<TVItCat, VItCat> //
|| (is_same_v<TVItCat, random_access_iterator_tag> && is_same_v<VItCat, contiguous_iterator_tag>) );
}

if constexpr (forward_range<const V>) {
STATIC_ASSERT(is_same_v<typename iterator_traits<iterator_t<const TV>>::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};

Expand All @@ -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);
}
};

Expand Down

0 comments on commit ebafd4e

Please sign in to comment.