浮点数的全局格式选项

时间:2015-10-05 09:12:46

标签: c++ c++11

我知道可能为基本类型重载(流)运算符,如下所示:

std::ostream & operator<<(std::ostream &stream, const double s) {
    stream << std::scientific << std::showpos << std::setprecision(15) << std::to_string(s);
    return stream;
}

为基本类型定义全局格式选项的首选方法是什么?请注意,我想将格式应用于任何类型的输出流,而不仅仅是std::cout等特定流。欢迎使用C ++ 11解决方案。任何提示?

4 个答案:

答案 0 :(得分:5)

您可以定义自己的操纵器来设置流格式化程序。您的操纵器必须符合<<操作员期望的格式:

basic_ostream& operator<<(
    std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );

例如:

template <class Char>
basic_ostream<Char>& format_double(basic_ostream<Char>& stream) {
    return stream << std::scientific 
                  << std::showpos 
                  << std::setprecision(15);
}

然后就这样做:

cout << format_double << 2.0;

<强>参考

备注

操纵器有两种格式,一种是ios_base作为参数,另一种是basic_ostream。您必须使用更晚的版本,因为未指定setprecision(int)的返回值。例如,我的编译器(gcc-4.9)返回一个包含整数的结构_Setprecision,并为此结构和<<定义一个特定的运算符basic_ostream

答案 1 :(得分:2)

重载流是一个坏主意,但你可以包装它们。如果你想做一个特殊但常见的前/后处理,定义一个自定义(模板化)类,它有一个流作为成员(可能在构造函数中受到影响),并在预处理输入和/或执行某些操作后将实际的io委托给该流后处理。

class Printer {
    ostream &ost;

    Printer(ostream& st): ost(st) {
        // other initializations ...
    }

    Printer& operator << (double d) {
        ost << std::scientific << std::showpos << std::setprecision(15) << std::to_string(s);
        return *this;
    }
    // others: ostream conversion, other processing...
}

答案 2 :(得分:2)

可以通过确保流使用不同的std::locale来修改数值类型(整数和浮点数)的格式。此工具可以用于实现设置全局std::locale后创建的所有流的格式。现有的流也可以通过std::locale来使用此修改后的imbue()

示例可能如下所示:

class special_num_put
    : public std::num_put<char> {
    virtual iter_type do_put(iter_type it, ios_base& fmt,
                             char_type fill, double v) const {
        fmt.precision(15);
        fmt.setf(std::ios_base::showpos);
        fmt.setf(std::ios_base::scientific, std::ios_base::floatfield);
        return this->std::num_put<char>::do_put(it, fmt, fill, v);
    }
    // likewise for all of the other numeric types
};

int main() {
    std::locale::global(std::locale(std::locale(), new special_num_put));
    std::cout.imbue(std::locale()); // deal with existing stream
    // likewise for all other preexisting streams
}

请注意,我同意之前的评论,您应该想要做这样的事情。

答案 3 :(得分:0)

要展开fjardon's answer,您可以使用模板为任何类型创建默认格式,例如

cout << formatted(2.0) << ' ' << formatted(1.4,6) << ' ' << formatted(2.3f)

使用不同的精度等。这可以通过

实现
namespace io_formatting {
  template<typename Tp>
  struct manipulator
  {
    Tp  val;
    int prec;
    manipulator(Tp x, int p=std::numeric_limits<Tp>::digits10)
    : val(x), prec(p) {}        
  };
  template<typename X>
  inline std::ostream& operator<<(std::ostream&o, manipulator<X> const&m)
  {
    return o << std::scientific 
             << std::showpos 
             << std::setprecision(m.prec)
             << m.val;
  }
}
template<typename Tp>
io_formatting::manipulator<Tp> formatted(Tp x) { return {x}; }
template<typename Tp>
io_formatting::manipulator<Tp> formatted(Tp x, int p) { return {x,p}; }

您可以使用专门化和/或SFINAE来区分不同类型(浮点,积分,复杂......)。