【问题标题】:Why aren't ranges' algorithms compatible with std's iterators?为什么范围的算法与 std 的迭代器不兼容?
【发布时间】:2019-02-25 09:15:21
【问题描述】:
#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 的迭代器不兼容?

【问题讨论】:

  • 主要是因为范围支持是实验性的,还不是标准的,所以std::ostream_iterator 的设计没有任何范围支持。重点是证明将这种支持正式引入未来标准的可行性,而不是锁定完整的规范。据推测,如果在标准的未来版本中引入范围,ranges::ostream_iterator 的规范将成为 @ 规范的一部分987654327@ 和 ranges::copy() 将成为 std::copy() 规范的一部分,并且将解决任何不兼容问题。
  • 彼得的回答不太准确。 ranges::copy 有意要求其输出迭代器是默认可构造的。而ranges::copy 将保留ranges::copy(准确地说是std::ranges::copy)并且不会与std::copy 合并。请参阅下面的 Barry 的回答。
  • @EricNiebler:ranges::copy 是否需要默认构造其输出迭代器? (为什么?)如果不是,这似乎是不必要的不​​兼容......
  • 你用 C++20 试过了吗,en.cppreference.com/w/cpp/iterator/ostream_iterator/…std::ostream_iterator 是默认可构造的,这意味着从讨论中,它可以工作。
  • @Nemo,我有这种感觉,范围总是要求比它需要的更多。我也问自己,为什么复制需要迭代器的默认构造?也许这意味着我没有正确考虑这个问题。也许是迭代器是正确的值类型的全面要求,因此特别是默认可构造的。但是对于任何特定的算法,似乎总是潜伏着一个较弱的概念。我曾经对语法上需要默认构造的算法进行了一次实证调查:我在 STL 中只能找到 2 个,而且它们在实现中似乎是无偿的

标签: c++ iterator c++-concepts c++20 range-v3


【解决方案1】:

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

这是正确的。并不是ranges::copy 以某种方式识别ranges::ostream_iterator 而不是std::ostream_iterator。 Ranges 对 OutputIterator 是什么有一个精炼的概念,例如 ranges::ostream_iterator 对 OutputIterator 进行建模,但 std::ostream_iterator 没有

具体来说,ranges::copy() 需要 WeaklyIncrementable&lt;O&gt;,它精炼了需要 DefaultConstructibleSemiRegular&lt;O&gt;ranges::ostream_iterator 是默认可构造的,但 std::ostream_iterator 不是。

因此失败了。


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


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


请注意,range-v3/Ranges TS/Ranges Proposal 概念 OutputIterator 与标准库现有的 OutputIterator 概念是分开的。 std::ostream_iterator 不模拟前者,但它确实 模拟后者 - 所以今天使用 std::copystd::ostream_iterator 非常好。在 P0896 之后,使用 ranges::copystd::ostream_iterator 也可以 - 因为建议对 std::ostream_iterator 进行更改。

【讨论】:

  • 是的,好多了,也不那么可怕了:)
  • 嗯...ranges::ostream_iterator 怎么会是默认可构造的?它不应该需要一个ostream吗?
  • @einpoklum 不需要 - 你以后可以随时分配。
  • @Barry :我认为如今将“官方”构造与“有效”构造分开是一种禁忌。你甚至可以用ranges::ostream_iterator {} 做任何事情吗?
  • @Barry:奇怪;我刚刚在separate question 中问过这个问题。
猜你喜欢
  • 2017-02-07
  • 2020-12-20
  • 2021-10-28
  • 1970-01-01
  • 2022-07-11
  • 2013-03-29
  • 1970-01-01
  • 2014-03-15
相关资源
最近更新 更多