a question about overloading operator<<

J

JustSomeGuy

I have a double that I want to output as: (depending on its value)

1000 Bytes
1.6 Kilobyte
2.5 Megabytes
..5 Terabytes

can I do this with...

ostream & operator<<(ostream & o, double n)


How would you recommend going about outputting this?
 
V

Vyacheslav Kononenko

JustSomeGuy said:
I have a double that I want to output as: (depending on its value)

1000 Bytes
1.6 Kilobyte
2.5 Megabytes
.5 Terabytes

can I do this with...

ostream & operator<<(ostream & o, double n)
No you cannot. Operators for standard types have been already defined.
How would you recommend going about outputting this?
Just make a wrapper around double:

class BytesFormat {
public:
BytesFormat( double d_ ) : d( d_ ) {}
friend std::eek:stream &operator<<( std::eek:stream &os, const BytesFormat
&bt );
private:
double d;
};

void foo()
{
double bytes;
// ...

std::cout << BytesFormat( bytes );
}


std::eek:stream &operator<<( std::eek:stream &os, const BytesFormat &bt )
{
if( bt.d < 1000.0 ) os << d << " Bytes";
// ...
return os;
}
 
D

Dietmar Kuehl

No you cannot. Operators for standard types have been already
defined.

.... but still you can achieve the above goal! All you need to do is
to create a new "num_put" facet (i.e. a class derived from
'std::num_put<char>'), install this facet into a 'std::locale' object,
and 'imbue()' the stream with the resulting object. There is no need
for falling back to ill-advised techniques.
 
V

Vyacheslav Kononenko

Dietmar said:
defined.

... but still you can achieve the above goal! All you need to do is
to create a new "num_put" facet (i.e. a class derived from
'std::num_put<char>'), install this facet into a 'std::locale' object,
and 'imbue()' the stream with the resulting object. There is no need
for falling back to ill-advised techniques.

Cool. How about to print regular doubles and kilobytes at the same time?
 
T

Tom Widmer

Cool. How about to print regular doubles and kilobytes at the same time?

You'd have to also write a manipulator to set a custom flag on the
stream and have the num_put facet obtain the formatting information
from the stream (in the ios_base& parameter) before deciding how to
output the number.

This is all a little involved, but you could write a reusable
framework to make it easier (and boost may have one already, just not
in a released version).

Tom
 
O

Old Wolf

Dietmar Kuehl said:
defined.

... but still you can achieve the above goal! All you need to do is
to create a new "num_put" facet (i.e. a class derived from
'std::num_put<char>'), install this facet into a 'std::locale' object,
and 'imbue()' the stream with the resulting object.

You make it sound so easy :)
 
T

Tom Widmer

You make it sound so easy :)

There's definitely room for a boost library to make it easier, so that
you can, for example, just change the formatting of double without
having to worry about the other numeric types or formatting options,
etc.

Tom
 
D

Dietmar Kuehl

Old said:
You make it sound so easy :)

That would be because it actually *is* easy! The only tricky part is
the actual formatting since the above is hardly a specification. Here
is some sample code:

| #include <locale>
| #include <iostream>
| #include <sstream>
| #include <algorithm>
|
| struct my_num_put:
| std::num_put<char>
| {
| iter_type do_put(iter_type to, std::ios_base& fmt,
| char fill, long double d) const
| {
| std::eek:stringstream out;
| out.precision(1);
| out << std::fixed;
| if (d < 1024.0)
| out << d << " Bytes";
| else if (d < 1024.0 * 1024.0)
| out << (d / 1024.0) << " Kilobytes";
| else if (d < 1024.0 * 1024.0 * 1024.0)
| out << (d / (1024.0 * 1024.0)) << " Megabytes";
| else if (d < 0.5 * 1024.0 * 1024.0 * 1024.0 * 1024.0)
| out << (d / (1024.0 * 1024.0 * 1024.0)) << " Gigabytes";
| else
| out << (d / (1024.0 * 1024.0 * 1024.0 * 1024.0))
| << " Terabytes";
|
| std::string const& s = out.str();
| return std::copy(s.begin(), s.end(), to);
| }
| iter_type do_put(iter_type to, std::ios_base& fmt,
| char fill, double d) const
| {
| return do_put(to, fmt, fill, static_cast<long double>(d));
| }
| };
|
| int main()
| {
| std::locale loc;
| std::locale my_loc(loc, new my_num_put);
| std::cout.imbue(my_loc);
|
| std::cout << 1000.0 << "\n";
| std::cout << 1600.0 << "\n";
| std::cout << 2500000.0 << "\n";
| std::cout << 550000000000.0 << "\n";
| }

This is hardly rocket science...

Note a. that this code does indeed just what I decribed before and b.
most of the work goes into actually figuring out the right format. But
even then, it is no big deal.

BTW, if you want to have something like this which you could turn
on/off
at will, you would have to set formatting flags in the stream object to
tell the stream when you want which formatting. The location to store
e.g. a flag is in an 'int' object accessed using the stream's 'iword()'
object. However, this is no big deal either...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top