除了上一个答案之外,您还可以选择创建自己的std::num_get<char>
facet 以将自定义输入解析无缝集成到 IOStreams 接口中。
如果您在读入整数时碰巧输入了浮点文字,则流仍将解析尽可能多的字符,只要这些字符可以在您要提取的数据类型中使用。当流找到流的结尾、空白字符或不符合类型格式要求的字符时,它才会停止读取。在我们的例子中,流将找到字符.
然后停止读取。
结果是即使部分输入已被消耗,读取也被认为是成功的。但是,下一次读取将不成功,因为下一个字符是 a .
,它在整数中不可用。
这是我们将用于自定义方面的信息。在读取输入后,我们只需检查下一个字符是否为小数点。如果它是,您有几个选项来报告错误:
你可以...
输出错误信息
输出错误信息对控制台用户来说是最方便的,但不符合 IOStreams 的设计。当检测到错误输入时,流不会将错误消息输出到控制台,因此您的方面也不应该。
抛出异常
您可以抛出异常,但请注意它们不会传播到流之外。这是因为默认情况下流被编程为不抛出异常。相反,std::ios_base::badbit
只要检测到异常,它们就会在流中设置。您必须exceptions()
在执行输入之前或之后在流上设置掩码以捕获异常。另一个需要注意的是,只有std::ios_base::failure
从溪流中抛出,所以你只能抓住它。
设置流状态
设置流状态对您方面的用户最有意义,并且符合 IOStreams 的设计。这样,您就不必彻底改变使用流的方式。只需在流状态下检查输入是否成功,就像您自然地使用普通方面一样。
设置流状态是我们将在以下代码中使用的方法:
#include <locale>
class num_get : public std::num_get<char>
{
public:
// Override do_get which is a virtual function in the std::num_get<char>
// base class. It is called by the public member function get() in the
// implementation of std::basic_istream<charT>::operator>>(int&)
// You might want to put this into a helper function and call it in
// both the signed and unsigned overloads
iter_type do_get( iter_type it, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long& v ) const
{
// Store a locale object for later use.
std::locale loc(str.getloc());
// delegate the extraction to the default base class function
it = std::num_get<char>::do_get(it, end, str, err, v);
// If the extraction succeeded, tell the user if positive or negative,
// or zero
if (!(err & std::ios_base::failbit))
{
if (v == 0)
std::cout << "The number you entered is a zero.\n";
std::cout << "You entered a " <<
((v >= 0) ? "positive" : "negative") << " number.\n";
// Check whether the end has not been met (because of further
// input that can't be used in a long). And if the first character
// of that input is a decimal point (or '.' in en_US) then get
// rid of that input for convenience, and set failbit
if (it != end && *it == std::use_facet<std::numpunct<char>>(loc).decimal_point())
{
// We get rid of that input by calling the base class function
// again which does all the necessary parsing.
// Note that if you do not want to get rid of the invalid
// floating point input, then simply remove these two lines.
it = std::num_get<char>::do_get(++it, end, str, err, v);
// Clear out v
v = 0;
// set failbit
err |= std::ios_base::failbit;
}
}
return it;
}
};
要在流中设置此构面,请将其安装到语言环境中并将该语言环境“灌输”到流中。像这样:
// Create a new locale with std::num_get<char> facet replaced by our custom facet
std::locale new_locale(std::cin.getloc(), new num_get);
// Imbue this new locale into std::cin
std::cin.imbue(new_locale);
完成后无需删除构面。这由持有它的语言环境的析构函数处理。
如果您想获得不同的行为,则应在实际使用流之前完成本地化设置。
Live Example