为什么范围的算法与 std 的迭代器不兼容?

2022-01-10 00:00:00 iterator c++ c++20 c++-concepts range-v3
#include <vector>
#include <iostream>
#include <range/v3/all.hpp>

int main()
{
    auto coll = std::vector{ 1, 2, 3 };

    ranges::copy(
        coll,
        ranges::ostream_iterator<int>{  std::cout, ", " }
    ); // ok

    ranges::copy(
        coll, 
        std::ostream_iterator<int>{ std::cout, ", " }
    ); // error 
}

上面的代码显示了问题.我使用 ranges-v3-0.3.7.

The issue is shown in the code above. I use ranges-v3-0.3.7.

对我来说,通用算法 copy 不应该关心目标迭代器类型,只要它满足输出迭代器的要求.

To me, the generic algorithm copy shouldn't care about the destination iterator type as long as it meets the requirements of output iterator.

如果是这样,为什么范围的算法与 std 的迭代器不兼容?

If so, why aren't ranges' algorithms compatible with std's iterators?

推荐答案

对我来说,通用算法 copy 不应该关心目标迭代器类型,只要它满足输出迭代器的要求.

To me, the generic algorithm copy shouldn't care about the destination iterator type as long as it meets the requirements of output iterator.

这是正确的.并不是 ranges::copy 以某种方式识别 ranges::ostream_iterator 而不是 std::ostream_iterator.就是 Ranges 对 OutputIterator? 的概念有一个完善的概念,例如 ranges::ostream_iterator 对 OutputIterator 进行建模,但 std::ostream_iterator 没有.

This is correct. It's not that ranges::copy somehow recognizes ranges::ostream_iterator and not std::ostream_iterator. It's that Ranges has a refined concept for what an OutputIterator? is, such that ranges::ostream_iterator does model OutputIterator but std::ostream_iterator does not.

具体来说,ranges::copy() 需要 WeaklyIncrementable<O> 精炼 SemiRegular 需要 DefaultConstructible.范围::ostream_iterator 是默认可构造的,但 std::ostream_iterator 不是.

Specifically, ranges::copy() requires WeaklyIncrementable<O> which refines SemiRegular<O> which requires DefaultConstructible. ranges::ostream_iterator is default constructible, but std::ostream_iterator is not.

因此失败了.

在 P0896 中,基于范围的 copy() 算法确实需要 WeaklyIncrementable(因此也需要 DefaultConstructible)作为其输出迭代器 - 但通过添加一个std::ostream_iterator 的默认构造函数(参见第 70 页).

In P0896, the range-based copy() algorithm does require WeaklyIncrementable (and thus DefaultConstructible) for its output iterator - but addresses this mismatch by also adding a default constructor to std::ostream_iterator (see page 70).

作为对此的更新,P2325R3 刚刚被 C++20 追溯采用,它恢复了这一变化.std::ostream_iterator 将不再是默认可构造的,并且 weakly_incrementable 概念将不再需要默认构造(以及其他更改).

As an update to this, P2325R3 was just adopted retroactively for C++20, which reverts this change. std::ostream_iterator will no longer be default constructible and the weakly_incrementable concept will no longer require default constructibility (among other changes).

? 请注意,range-v3/Ranges TS/Ranges Proposal 概念 OutputIterator 与标准库现有的 OutputIterator 概念是分开的.std::ostream_iterator 不为前者建模,但它确实 为后者建模 - 因此将 std::copystd 一起使用::ostream_iterator 今天很好.在 P0896 之后,将 ranges::copystd::ostream_iterator 一起使用也可以――因为建议对 std::ostream_iterator 进行更改代码>.

? Note that the range-v3/Ranges TS/Ranges Proposal concept OutputIterator is separate from the standard library's existing concept of OutputIterator. std::ostream_iterator does not model the former but it does model the latter - so using std::copy with a std::ostream_iterator today is perfectly fine. And post-P0896, using ranges::copy with a std::ostream_iterator will also be fine - because of the proposed changes to std::ostream_iterator.

相关文章