C++ 浮点数的全局格式选项

C++ 浮点数的全局格式选项,c++,c++11,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::

我知道不可能按如下方式重载(流)基元类型的运算符:

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

std::ostream&operator您可以定义自己的操纵器来设置流格式化程序。您的操纵器必须符合
所期望的格式重载流是个坏主意,但您可以包装它们。如果要执行特殊但常见的预/后处理,请定义一个自定义(模板化)类,该类将流作为成员(可能在构造函数中受影响),并在预处理输入后将实际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...
}
类打印机{
奥斯特雷姆和奥斯特;
打印机(ostream&st):ost(st){
//其他初始化。。。
}
打印机和操作员要展开,可以使用模板为任何类型创建默认格式,例如

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

数值类型(整数和浮点数)的格式可通过确保流使用不同的
std::locale
进行修改。此功能可用于对设置全局
std::locale
后创建的所有流进行格式化。也可通过
imbue()
使现有流使用此修改的
std::locale

一个例子可以如下所示:

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
}
类特殊数量\u put
:public std::num_put{
虚拟国际热核聚变实验堆类型(国际热核聚变实验堆类型it、ios基础和fmt、,
字符类型填充,双v)常数{
fmt.精度(15);
fmt.setf(标准::ios_base::showpos);
fmt.setf(std::ios_base::scientific,std::ios_base::floatfield);
返回这个->std::num\u put::do\u put(it、fmt、fill、v);
}
//对于所有其他数字类型也是如此
};
int main(){
std::locale::global(std::locale(std::locale(),new special_num_put));
std::cout.imbue(std::locale());//处理现有流
//对于所有其他先前存在的流也是如此
}

请注意,我同意前面的评论,即您应该不想做类似的事情。

您可以定义一个应用所需选项的操纵器。显式是好的,隐式是坏的。大致上。您不应该(想)即使有可能,也要这样做。这会使你的代码更难理解和维护。@Cheersandhth.-Alf你能说得更清楚一点吗?正是我要说的!+1好建议,但我敢打赌,人们至少会在代码的某些地方忘记操纵器(如果你在团队中工作,这一点尤其正确)在某些应用程序中,浮点数的格式总是相同的。你应该说明为什么重载流是个坏主意。@Walter:因为许多标准库类都不是为重载而设计的(没有虚拟析构函数,没有办法让标准流实现自定义类)这是一个与fjardon完全不同的答案。这更多地遵循“漂亮的打印机”方法,而不是操纵器概念。
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...
}
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}; }
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
}