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

Why aren't ranges' algorithms compatible with std's iterators?

#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.

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

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

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 不会 .

具体来说,ranges::copy() requires WeaklyIncrementable<O> which refines SemiRegular<O> which requires DefaultConstructible. ranges::ostream_iterator is default constructible, but std::ostream_iterator 不是。

因此失败。


P0896 中,基于范围的 copy() 算法确实需要 WeaklyIncrementable(因此需要 DefaultConstructible)作为其输出迭代器 - 但通过还添加来解决这种不匹配std::ostream_iterator(参见第 70 页)的默认构造函数。


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


请注意,range-v3/Ranges TS/Ranges 提案概念 OutputIterator 与标准库中现有的 OutputIterator 概念是分开的。 std::ostream_iterator 不模拟前者,但它 模拟后者 - 所以今天使用 std::copystd::ostream_iterator 是完全没问题的。 post-P0896,将 ranges::copystd::ostream_iterator 一起使用也可以 - 因为建议更改 std::ostream_iterator.