如果流可以读取任何整数值,则整数值的正常提取会成功。也就是说,如果至少有一位数字可选地后跟任何内容,则整数读取成功。正常的提取操作don't尝试阅读更多内容,特别是他们不会尝试找到下一个空白。
从它的声音来看,您需要确保您的号码后面有一个空格,如果没有则失败。我可以想到两种不同的方法来做到这一点:
- 创建一个简单的操纵器,用于检查流是否位于空白字符上。然而,这意味着您将使用类似的方法来读取您的值
in >> value >> is_space
.
- 创建自定义
std::num_get<char>
侧面,将其安装到std::locale
, and imbue()
this std::locale
进入您的信息流。它涉及更多一些,但不需要对整数的读取方式进行任何更改。
创建这样的操纵器相当简单:
std::istream& is_space(std::istream& in)
{
if (!std::isspace(in.peek()))
{
in.setstate(std::ios_base::failbit);
}
return in;
}
现在,改变数字的读取方式更有趣,我怀疑我刚刚命名了许多大多数人都不太了解的标准库类。因此,让我们也快速为此键入一个示例。我会改变std::num_get<char>
只处理方面unsigned int
:要对其他整数类型执行此操作,需要重写更多函数。所以,这里有一个替代品std::num_get<char>
facet:
class num_get:
public std::num_get<char>
{
iter_type do_get(iter_type it, iter_type end,
std::ios_base& ios, std::ios_base::iostate& err,
unsigned int& value) const
{
it = std::num_get<char>::do_get(it, end, ios, err, value);
if (it != end && !isspace(static_cast<unsigned char>(*it)))
{
err |= std::ios_base::failbit;
}
return it;
}
};
所有这一切都是从派生一个类std::num_get<char>
并重写其虚拟函数之一。这个函数的实现相当简单:首先通过委托给基类来读取值(我刚刚意识到虚拟函数确实想要保护而不是像我过去那样私有,但这是一个完全不同的讨论) 。与是否成功无关(如果不成功,它将在 err 中设置错误状态),覆盖会检查是否有另一个可用字符,如果有,则检查它是否是空格,如果不是则设置一个std::ios_base::failbit
在错误结果中err
.
剩下的就是设置流以在std::locale
并挂钩新的std::locale
进入流:
std::locale loc(std::locale(), new num_get);
in.imbue(loc);
The std::locale
s 及其构面是内部引用计数的,即您不应该跟踪指向构面的指针,也不需要保留std::locale
周围任一。如果觉得太麻烦imbue()
所创造的std::locale
或者你想在任何地方使用这个修改后的逻辑,你可以设置全局std::locale
它用于初始化任何新创建的流以使用自定义std::num_get<char>
facet.