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

This commit is contained in:
A. Jiang 2022-08-06 07:22:50 +08:00 коммит произвёл GitHub
Родитель 9ed0e6bd89
Коммит 3e046a483e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 60 добавлений и 11 удалений

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

@ -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;
@ -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;

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

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