为什么 C++ istreams 只允许格式化读取现有变量?

Why do C++ istreams only allow formatted-reading into an existing variable?

提问人:einpoklum 提问时间:5/21/2022 最后编辑:einpoklum 更新时间:5/21/2022 访问量:96

问:

在C++中(并使用标准库工具),如果我想从标准输入中读取整数,我需要这样做:

int x;
std::cin >> x;

查看 cpppreference 上的 std::istream 页面,似乎没有返回 prvalue 之类的函数;也没有一个独立的功能可以做到这一点。std::cin.scan<int>()intstd::scan<int>(std::cin)

我的问题是:为什么?

在我看来,鼓励人们这样做似乎是荒谬的:

  1. 定义并命名他们可能不需要的变量(例如,与 .func_taking_an_int(std::cin.scan<int>())
  2. 拆分变量的定义和初始化

那么,只支持运算符形式的理由是什么呢?

现在,我知道C++ istreams可以追溯到几十年前,但这对我来说仍然很奇怪(更不用说以后可以添加额外的方法/函数)。


动机:我看到这个问题,并意识到,令我们感到羞愧的是,除了使用未初始化的变量之外,我们无法为发帖人提供更好的方法来编写他们的程序。我假设,当然,我们可以帮助该海报将定义带入与初始化相同的语句中......但似乎我们不能。

C++ IOSTREAM 习语 istream

评论

2赞 Alan Birtles 5/21/2022
您将在哪里检查读取是否成功?func_taking_an_int(std::cin.magic<int>())
0赞 einpoklum 5/21/2022
@AlanBirtles:里面。如果失败,它就会抛出。scan()
0赞 sweenish 5/21/2022
这似乎是一个很好的建议。不过,我个人更喜欢更类似于 python 的东西。我还想要一个标准的Unicode解决方案,而不是今天被指的半生不熟的垃圾。input()
0赞 einpoklum 5/21/2022
@sweenish:我敢打赌,这样的事情一定被讨论过,但被拒绝了......
0赞 Aykhan Hagverdili 5/21/2022
@einpoklum可选而不是投掷怎么样?我发现 IO 故障太常见了,不可能是“例外”,所以我宁愿明确说明这一点。

答:

2赞 Aykhan Hagverdili 5/21/2022 #1

当然有一个:

#include <iostream>
#include <iterator>

int main() {
  auto const i = *std::istream_iterator<int>(std::cin);
}

请注意,如果没有有效的 .你可能希望它引发异常,但由于 iostreams 早于异常,因此 API 的工作方式不是这样。您应该将其与结束迭代器进行比较。std::cinint

std::istream_iterator<int> it(std::cin), end;
auto const i = (it != end) ? *it : -1;

最后,您可能希望将其包装在一个很好的、可重用的 API 中:

#include <iostream>
#include <iterator>
#include <optional>

template <class T>
auto scan(std::istream& is) -> std::optional<T> {
  std::istream_iterator<int> it(std::cin), end;
  if (it != end) return std::optional(*it);
  return std::nullopt;
}

int main() {
  auto const i = scan<int>(std::cin);
  if (i) {
    return *i;
  }
  return -1;
}

评论

1赞 sweenish 5/21/2022
这很酷,但“有一个”与“你必须自己写”不同。
1赞 Aykhan Hagverdili 5/21/2022
@sweenish第一个片段正是 OP 想要的,减去错误检查,因为 iostream 早于异常。它在标准库中。
0赞 Remy Lebeau 5/21/2022
return std::optional(*it);应该只是但坦率地说,如果你要写一个返回一个的扫描函数,我根本不会费心使用,只是检查返回状态,例如:return *it;optionalistream_iteratoroperator>>template <class T> std::optional<T> scan(std::istream& is) { T t; if (std::cin >> t) return t; return std::nullopt; }
0赞 einpoklum 5/21/2022
真的是UB吗?它不会触发异常吗?另外,为什么我要使用 istream 迭代器,而不仅仅是定义局部变量并返回它?依靠NRVO?无论如何,这个建议与问题无关,因为我不是在问可以写什么,而是在问标准库中有什么。scan()
0赞 cigien 5/21/2022
@einpoklum 没有解决你问题的突出部分吗?即不需要额外的变量。std::istream_iterator<int>(std::cin)