I know it is not possible to overload (stream) operators for primitive types as follows:
std::ostream & operator<<(std::ostream &stream, const double s) {
stream << std::scientific << std::showpos << std::setprecision(15) << std::to_string(s);
return stream;
}
What is the preferred way for defining global formatting options for primitive types? Note that I want to apply the formatting to any kind of output stream, not only specific streams like std::cout
. C++11 solutions are welcome. Any hints?
You could define your own manipulator for setting up the stream formatters. Your manipulator must conform to the format expected by the <<
operator:
basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );
So for instance:
template <class Char>
basic_ostream<Char>& format_double(basic_ostream<Char>& stream) {
return stream << std::scientific
<< std::showpos
<< std::setprecision(15);
}
Then just do:
cout << format_double << 2.0;
References
Notes
There are two format for manipulators, one takes a ios_base
as argument and the other a basic_ostream
. You must use the later because it is not specified what is the return value of setprecision(int)
. For instance, my compiler (gcc-4.9) returns a struct _Setprecision
holding the integer and defines a specific operator <<
for this struct and basic_ostream
.
Overloading streams is a bad idea, but you can wrap them. If you want to do a special but common pre/post-processing, define a custom (templated) class that has a stream as member (maybe affected in constructor), and delegates actual io to that stream after preprocessing input and/or do some post-processing after.
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...
}
The formatting of the numeric types (integers and floating point numbers) can be modified by making sure streams are using a different std::locale
. This facility can be used to effect the formatting of all streams which are created after the global std::locale
is set. Existing streams can also be made to use this modified std::locale
by imbue()
ing.
An example could look something like this:
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
}
Note that I agree with the comment made earlier that you should not want to do anything like that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With