首页 > 解决方案 > 定义transform_view​::iterator的iterator_category的问题?

问题描述

该标准在[range.adaptors]中定义了各种范围适配器,其中一些具有自己的迭代器类型。

为了标准化iterator_category这些迭代器,该标准还指定了它们的定义方式。例如,在[range.transform.iterator-2]中,iterator_categoryoftransform_view​::​iterator的定义如下:

当且仅当models 定义成员typedef-name 。在这种情况下, 定义如下:让表示类型。iterator_­categoryBaseforward_­rangeiterator​::​iterator_­categoryCiterator_­traits<iterator_­t<Base>>​::​iterator_­category

如果is_­lvalue_­reference_­v<invoke_­result_­t<F&, range_­reference_­t<Base>>>true,那么

  • 如果C模型 derived_­from<contiguous_­iterator_­tag>iterator_­category 表示random_­access_­iterator_­tag

  • 否则,iterator_­category表示C

否则,iterator_­category表示input_­iterator_­tag

但是这个定义似乎有一些问题,考虑以下情况

vector v{1, 2, 3, 4, 5};
auto r = views::iota(0, 5) | 
         views::transform([&](int i) -> int& { return v[i]; });

using I = ranges::iterator_t<decltype(r)>;
static_assert(random_access_iterator<I>);
static_assert(same_as<I::iterator_concept, random_access_iterator_tag>);

static_assert(__detail::__cpp17_randacc_iterator<I>);
static_assert(same_as<I::iterator_category, input_iterator_tag>);

由于在 C++20 中r是完美的,它的迭代器模型,然而,根据上面的描述,由于is only ,迭代器的 也是 only 。random_access_rangerandom_access_iteratoriota_view::iterator_categoryinput_iterator_tagiterator_categoryIinput_iterator_tag

但是很明显,iteratorI满足了 的所有要求,所以如果它的isLegacyRandomAccessIterator应该更合理。iterator_categoryrandom_access_iterator

这是标准缺陷吗?还是这背后有考虑?

标签: c++c++20std-ranges

解决方案


根据 C++20,a 的迭代器类别transform_view 确定如下

iterator​::​iterator_­category定义如下:C表示类型iterator_­traits<iterator_­t<Base>>​::​iterator_category

  • 如果is_­lvalue_­reference_­v<invoke_­result_­t<F&, range_reference_­t<Base>>>是真的,那么
    • 如果C模型derived_­from<contiguous_­iterator_­tag>iterator_­category表示random_­access_­iterator_­tag
    • 否则,iterator_­category表示C
  • 否则,iterator_­category表示input_­iterator_tag

因此,如果您的仿函数返回左值引用,则迭代器类别派生自基本迭代器类型的迭代器类别。提供基本迭代器的基本范围是views::iota.

但是,因为iota是纯右值范围(它的迭代器返回纯右值,而不是引用),所以它 iterator_category 不能是std::input_iterator_tag. 所以在上面的文字中transform_viewC将是std::input_iterator_tag所以无论你的函子返回什么,类别transform_view都会是。std::input_iterator_tag

您应该真正避免关心iterator_category何时使用std::ranges基于 - 的代码。如果您知道您正在处理 C++20 范围,那么您应该使用iterator_concept.


推荐阅读