提问人:einpoklum 提问时间:5/21/2022 最后编辑:einpoklum 更新时间:5/21/2022 访问量:96
为什么 C++ istreams 只允许格式化读取现有变量?
Why do C++ istreams only allow formatted-reading into an existing variable?
问:
在C++中(并使用标准库工具),如果我想从标准输入中读取整数,我需要这样做:
int x;
std::cin >> x;
查看 cpppreference 上的 std::istream
页面,似乎没有返回 prvalue 之类的函数;也没有一个独立的功能可以做到这一点。std::cin.scan<int>()
int
std::scan<int>(std::cin)
我的问题是:为什么?
在我看来,鼓励人们这样做似乎是荒谬的:
- 定义并命名他们可能不需要的变量(例如,与 .
func_taking_an_int(std::cin.scan<int>())
- 拆分变量的定义和初始化
那么,只支持运算符形式的理由是什么呢?
现在,我知道C++ istreams可以追溯到几十年前,但这对我来说仍然很奇怪(更不用说以后可以添加额外的方法/函数)。
动机:我看到这个问题,并意识到,令我们感到羞愧的是,除了使用未初始化的变量之外,我们无法为发帖人提供更好的方法来编写他们的程序。我假设,当然,我们可以帮助该海报将定义带入与初始化相同的语句中......但似乎我们不能。
答:
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::cin
int
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;
optional
istream_iterator
operator>>
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)
评论
func_taking_an_int(std::cin.magic<int>())
scan()
input()