gpt4 book ai didi

c++ - 为什么我不能使用 istream_view 和 std::accumulate 来总结我的输入?

转载 作者:行者123 更新时间:2023-12-03 10:04:58 25 4
gpt4 key购买 nike

这个程序:

#include <ranges>
#include <numeric>
#include <iostream>

int main() {
auto rng = std::ranges::istream_view<int>(std::cin);
std::cout << std::accumulate(std::ranges::begin(rng), std::ranges::end(rng), 0);
}
应该对标准输入流上显示为文本的所有整数求和。但是 - 它不会编译。我知道 std::ranges::begin()std::ranges::end()存在,那是怎么回事?编译器告诉我它找不到合适的候选人;怎么了?

最佳答案

从开始到 C++17,一切都在 <algorithm>基于迭代器对:你有一个 iterator指的是范围的开头和一个 iterator指范围的末尾,始终具有相同的类型。
在 C++20 中,这是通用的。范围现在用 iterator 表示和一个 sentinel对于那个迭代器 - 其中 sentinel本身实际上不需要是任何类型的迭代器,它只需要是一种可以与其对应的迭代器进行比较的类型(这是 sentinel_for 概念)。
C++17 范围往往是†有效的 C++20 范围,但不一定是相反的方向。原因之一是能够拥有独特的 sentinel类型,但还有其他人,这也适用于这个问题(见下文)。
为了配合新模型,C++20 在 std::ranges 中添加了大量算法。采用 iterator 的命名空间和一个 sentinel , 而不是两个 iterator s。例如,虽然我们一直都有:

template<class InputIterator, class T>
constexpr InputIterator find(InputIterator first, InputIterator last,
const T& value);
我们现在还有:
namespace ranges {
template<input_­iterator I, sentinel_­for<I> S, class T, class Proj = identity>
requires indirect_­binary_­predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr I find(I first, S last, const T& value, Proj proj = {});

template<input_­range R, class T, class Proj = identity>
requires indirect_­binary_­predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr borrowed_iterator_t<R>
find(R&& r, const T& value, Proj proj = {});
}
这里的第一个重载需要一个 iterator/ sentinel对,第二个取而代之的是一个范围。

虽然很多算法在 std::ranges 中加入了相应的重载, <numeric> 中的那些被排除在外。有一个 std::accumulate但没有 std::ranges::accumulate .因此,我们目前唯一可用的版本是采用迭代器对的版本。否则,你可以只写:
auto rng = std::ranges::istream_view<int>(std::cin);
std::cout << std::ranges::accumulate(rng, 0);
不幸的是, std::ranges::istream_view是新的 C++20 范围之一,其标记类型与其迭代器类型不同,因此您不能传递 rng.begin()rng.end()进入 std::accumulate任何一个。
这通常给您留下两个选项(三个,如果您包括等待 C++23,它希望有一个 std::ranges::fold ):
  • 编写您自己的基于范围和基于迭代器哨兵的算法。哪个为fold很容易做到。

  • 或者
  • 有一个实用程序可以将 C++20 范围包装成与 C++17 兼容的范围:views::common .所以你可以这样:

  • auto rng = std::ranges::istream_view<int>(ints) | std::views::common;
    std::cout << std::accumulate(rng.begin(), rng.end(), 0);
    除非在这种特定情况下。 istream_view的迭代器不可复制,在 C++17 中所有迭代器都必须是。所以实际上没有办法提供基于 istream_view 的 C++17 兼容迭代器。 .您需要适当的 C++20 范围支持。 future std::ranges::fold将支持仅移动 View 和仅移动迭代器,但 std::accumulate永远不能。
    在这种情况下,只留下选项 1。

    †C++20 迭代器需要是默认构造的,这不是 C++17 迭代器的要求。因此,具有不可默认构造的迭代器的 C++17 范围将不是有效的 C++20 范围。

    关于c++ - 为什么我不能使用 istream_view 和 std::accumulate 来总结我的输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65312736/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com