在 C++20 中,当我std::ranges::views::take()
在 a 上使用时,迭代 take 视图之后std::ranges::istream_view()
的下一个标记将被跳过。istream_view
考虑以下 C++20 代码片段:
#include <iostream>
#include <ranges>
#include <sstream>
#include <vector>
#include <algorithm>
namespace rn = std::ranges;
int main() {
std::string input = "1 2 3 4 5 6 7 8 9 10";
std::istringstream input_stream(input);
std::vector<int> head;
rn::copy(rn::istream_view<int>(input_stream) | rn::views::take(5),
std::back_inserter(head));
int next_int = 0;
input_stream >> next_int;
for(auto x : head) std::cout << x << " ";
std::cout << next_int << std::endl;
}
当我在 g++14 或 clang++17 中编译并运行此代码时,会产生以下输出(注意缺少“6”):
1 2 3 4 5 7
Godbolt 链接:https://godbolt.org/z/vdGvx9666
为什么会发生这种情况?这是预期的行为吗?可以做些什么来解决这个问题?
这看起来像是的缺点
std::ranges::copy
。注意它的返回值是:
std::ranges::copy、std::ranges::copy_if、std::ranges::copy_result、std::ranges::copy_if_result - cppreference.com
现在,在您的例子中,输入迭代器类型是,
std::ranges::istream_view
并且这个东西指向最后一个元素复制后它必须读取(使用)下一个元素。这对于检测当前迭代器是否到达(流的)末尾是必要的。std::ranges::copy
因此,要获取迭代器的返回值,std::ranges::istream_view
必须超越最后一个元素并读取下一个元素,从而导致您正在观察的问题。请注意,旧方式
std::copy_n
以不同的方式定义以防止出现此问题:注意“可能的实现”以奇怪的方式增加了输入迭代器,并且输入迭代器未返回的事实。