更改inf的Visual C ++输出

时间:2012-09-26 23:37:26

标签: c++ visual-c++ io

在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是内置类型。

我承认我无法弄清楚如何搜索基本问题的答案......

谢谢!

1 个答案:

答案 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;
}
然而,我应该补充说,这很快就被打了一遍,而且测试极其极小。它适用于测试用例,可能适用于其他窄流。猜测一下,它可能需要更多的工作才能在广泛的流中正常工作。