编辑:为了避免在 double 周围使用包装器结构,我将 anistream
封装在包装器类中。
不幸的是,我无法弄清楚如何避免为double
. 对于下面的实现,我在 周围创建了一个包装器结构istream
,包装器类实现了输入法。输入法确定否定性,然后尝试提取双精度数。如果失败,它将开始解析。
编辑:感谢 sehe 让我更好地检查错误情况。
struct double_istream {
std::istream ∈
double_istream (std::istream &i) : in(i) {}
double_istream & parse_on_fail (double &x, bool neg);
double_istream & operator >> (double &x) {
bool neg = false;
char c;
if (!in.good()) return *this;
while (isspace(c = in.peek())) in.get();
if (c == '-') { neg = true; }
in >> x;
if (! in.fail()) return *this;
return parse_on_fail(x, neg);
}
};
解析例程的实现比我最初想象的要复杂一些,但我想避免尝试putback
整个字符串。
double_istream &
double_istream::parse_on_fail (double &x, bool neg) {
const char *exp[] = { "", "inf", "NaN" };
const char *e = exp[0];
int l = 0;
char inf[4];
char *c = inf;
if (neg) *c++ = '-';
in.clear();
if (!(in >> *c).good()) return *this;
switch (*c) {
case 'i': e = exp[l=1]; break;
case 'N': e = exp[l=2]; break;
}
while (*c == *e) {
if ((e-exp[l]) == 2) break;
++e; if (!(in >> *++c).good()) break;
}
if (in.good() && *c == *e) {
switch (l) {
case 1: x = std::numeric_limits<double>::infinity(); break;
case 2: x = std::numeric_limits<double>::quiet_NaN(); break;
}
if (neg) x = -x;
return *this;
} else if (!in.good()) {
if (!in.fail()) return *this;
in.clear(); --c;
}
do { in.putback(*c); } while (c-- != inf);
in.setstate(std::ios_base::failbit);
return *this;
}
此例程与默认double
输入的行为不同之处在于,-
如果输入是,例如,则不会使用字符"-inp"
。失败时,"-inp"
仍将在流中 for double_istream
,但对于常规istream
仅"inp"
将留在流中。
std::istringstream iss("1.0 -NaN inf -inf NaN 1.2");
double_istream in(iss);
double u, v, w, x, y, z;
in >> u >> v >> w >> x >> y >> z;
std::cout << u << " " << v << " " << w << " "
<< x << " " << y << " " << z << std::endl;
我系统上的上述代码段的输出是:
1 nan inf -inf nan 1.2
编辑:添加一个“iomanip”之类的助手类。当一个对象在链double_imanip
中多次出现时,它的作用就像一个切换。>>
struct double_imanip {
mutable std::istream *in;
const double_imanip & operator >> (double &x) const {
double_istream(*in) >> x;
return *this;
}
std::istream & operator >> (const double_imanip &) const {
return *in;
}
};
const double_imanip &
operator >> (std::istream &in, const double_imanip &dm) {
dm.in = ∈
return dm;
}
然后用下面的代码来试一试:
std::istringstream iss("1.0 -NaN inf -inf NaN 1.2 inf");
double u, v, w, x, y, z, fail_double;
std::string fail_string;
iss >> double_imanip()
>> u >> v >> w >> x >> y >> z
>> double_imanip()
>> fail_double;
std::cout << u << " " << v << " " << w << " "
<< x << " " << y << " " << z << std::endl;
if (iss.fail()) {
iss.clear();
iss >> fail_string;
std::cout << fail_string << std::endl;
} else {
std::cout << "TEST FAILED" << std::endl;
}
上面的输出是:
1 nan inf -inf nan 1.2
inf
来自 Drise 的编辑:我进行了一些编辑以接受最初未包含的变体,例如 Inf 和 nan。我还把它做成了一个编译的演示,可以在http://ideone.com/qIFVo查看。