如何用C++20 ranges库正确从输入流中读取数据?
关于C++20 ranges库从流中读取数据的问题
C++20引入了新的ranges库,为处理各类序列提供了循环及<algorithm>迭代器用法之外的替代方案。这种写法的语法风格很吸引我——我更倾向于把容器、容器连续段或算术序列视为整体对象,而非迭代器模式里的两个对象或循环里的多个零散对象,所以尝试调整编码风格来适配这个特性。
我重点关注从流中读取数据的场景:假设标准输入流中有数字1 2 3 4 5,需要把前三个数字存入std::array<int, 3>类型的数组v,再读取一个数字存入int类型的变量n,预期结果为v == [1, 2, 3]且n == 4。
可行的传统实现方式
- 简单循环写法:
for (int i = 0; i < 3; ++i) std::cin >> v[i]; std::cin >> n;
这种方式逻辑直接,能得到预期结果。
- 传统迭代器方式:
std::copy_n(std::istream_iterator<int>(std::cin), 3, v.begin()); std::cin >> n;
该代码同样能得到v == [1, 2, 3], n == 4的正确结果。
使用ranges库遇到的问题
尝试用ranges库实现相同功能时,所有尝试的方式都得到v == [1, 2, 3], n == 5的结果,仿佛读取v时额外读取并丢弃了数字4,具体尝试的写法如下:
- 直接给传统
copy_n加上::ranges:
std::ranges::copy_n(std::istream_iterator<int>(std::cin), 3, v.begin()); std::cin >> n;
- 用
std::views::istream替代std::istream_iterator,结合copy_n:
std::ranges::copy_n(std::views::istream<int>(std::cin).begin(), 3, v.begin()); std::cin >> n;
- 用
std::views::istream结合take适配器和copy:
std::ranges::copy(std::views::istream<int>(std::cin) | std::ranges::views::take(3), v.begin()); std::cin >> n;
更严重的是,当尝试从std::istream读取0个元素时,只有循环方式能得到正确结果v == [0, 0, 0], n == 1,其他所有方式得到的结果都是v == [0, 0, 0], n == 2。
这些问题让我对使用std::ranges产生了疑虑,但我怀疑是自己理解有误:
- 是否可以用
std::ranges规范且可靠地从流中读取数据? - 是否有文档明确说明这一行为?
- 即使是传统迭代器方式,是否也需要单独处理读取0个元素的情况?
内容的提问来源于stack exchange,提问作者ivanovmp
相关产品推荐
相关产品推荐

