在Visual C ++中,如果我有一个值为inf的double,并使用流输出它:
double myval = std::numeric_limits<double>::infinity();
std::ostringstream msg;
msg << "This is infinite: " << myval;
结果是“1.#INF”。
是否有一种简单的方法可以简单地打印“inf”或“INF”?此字符串出现在随后将被解析的文本中,并且额外的字符会导致我们出现问题。
我想过将stream运算符重载为double,但double是内置类型。
我承认我无法弄清楚如何搜索基本问题的答案......
谢谢!
答案 0 :(得分:1)
这是可能的,但有点不重要,正确的做法是相当模糊的。
顺便说一句,我会注意到当你执行类似msg << myval;
的操作时,只有操作数的一个必须是用户定义的类型,这就是这里的情况(甚至虽然你没有定义它,但ostringstream
仍然是官方用户定义的类型)。但这或多或少都无关紧要。 operator<<
的现有重载将正常工作;你不需要自己提供。
我认为一个流是“媒人”。您有一个流缓冲区来处理实际的I / O,以及一个处理格式的区域设置。以这种方式思考,解决方案变得相当清楚:因为您想要更改的是格式,并且格式由区域设置处理,您需要更改区域设置。
然而,语言环境实际上是异构集合。具体来说,它是facet
类的集合。在这种情况下,我们关心的方面是num_put
方面。 num_put facet类具有各种类型的虚拟do_put
成员函数。我们在这种情况下关心的是double
:
template <class charT, class OutputIterator = std::ostreambuf_iterator<charT> >
class num_put : public std::num_put<charT, OutputIterator> {
public:
virtual iter_type do_put(iter_type i,
std::ios_base& b,
char_type fill,
double v) const
{
if (v == std::numeric_limits<double>().infinity()) {
static const char inf[]="inf";
std::copy(std::begin(inf), std::end(inf), i);
}
else {
std::ostringstream temp;
temp << v;
std::copy(temp.str().begin(), temp.str().end(), i);
}
return i;
}
};
要使用它,您可以使用包含该构面的区域设置来填充相关流:
int main() {
char *d="0";
std::locale loc(std::locale::classic(), new num_put<char>);
std::cout.imbue(loc);
std::cout << 1.0/atoi(d);
return 0;
}
然而,我应该补充说,这很快就被打了一遍,而且测试极其极小。它适用于测试用例,可能适用于其他窄流。猜测一下,它可能需要更多的工作才能在广泛的流中正常工作。