Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement LWG-3564: transform_view::iterator<true>::value_type and iterator_category should use const F& #2961

Merged
merged 11 commits into from
Aug 5, 2022
14 changes: 7 additions & 7 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -1908,11 +1908,11 @@ namespace ranges {

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>;
using iterator_category = conditional_t<
is_lvalue_reference_v<invoke_result_t<_Maybe_const<is_const_v<_Base>, _Fn>&, range_reference_t<_Base>>>,
frederick-vs-ja marked this conversation as resolved.
Show resolved Hide resolved
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>
Expand Down Expand Up @@ -1946,8 +1946,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>
strega-nil-ms marked this conversation as resolved.
Show resolved Hide resolved
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>>);
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
}

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