Stroustrup ["The C++ Programming Language, 4th Ed", pp 1097-1098] has provided an example of an interesting user-defined manipulator represented by the Format class.
The motivation is as follows:
Formatting is controlled by a multitude of separate flags and operations.
For example, all flags and operations exhibit “sticky” behavior (ie, they persist until explicitly changed), but a width() applies only to the next operation of certain types.
What we want is something that makes it simple to output a floating-point number in a predefined format without affecting future output operations on the stream.
Thus, we want to define the following:
a) a class that represents formats,
b) another that represents a format plus a value to be formatted and finally
c) an operator << that outputs the value to an ostream according to the format.
These abstractions are shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
class Format;
/// Format plus value
struct Bound_format
{
const Format& f;
double val;
};
class Format
{
private:
int prc; /// precision
/// width 0 means "as wide as necessary"
int wdt;
/// general, scientific or fixed
std::ios_base::fmtflags fmt;
friend std::ostream& operator<<(std::ostream&,
const Bound_format&);
///
public:
explicit Format(int p = 6,
std::ios_base::fmtflags f = {},
int w = 0) :
prc {p},
wdt {w},
fmt {f}
{
}
/// Make a Bound_format for *this and d
Bound_format operator() (double d) const
{
return Bound_format {*this, d};
}
Format& scientific()
{
fmt = std::ios_base::scientific;
return *this;
}
Format& fixed()
{
fmt = std::ios_base::fixed;
return *this;
}
Format& general()
{
fmt = {};
return *this;
}
Format& uppercase();
Format& lowercase();
Format& precision(int p)
{
prc = p;
return *this;
}
Format& width(int w)
{
wdt = w;
return *this;
}
Format& fill(char);
Format& plus(bool b = true); /// explicit plus
/// print trailing zeros
Format& trailing_zeros(bool b = true);
};
|
The output operator that takes a Bound_format as an argument is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
std::ostream& operator<<(std::ostream& os,
const Bound_format& bf)
{
std::ostringstream s;
s.precision(bf.f.prc);
s.setf(bf.f.fmt, std::ios_base::floatfield);
/// Compose string in s.
s << bf.val;
/// Output s to os.
return os << s.str();
}
|
The folowing program tests these abstractions and works fine:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
#include "Format.h"
using namespace std;
/// general format, precision 4
Format gen4 {4};
/// scientific format, precision 8
void testsci8(const double& d)
{
Format sci8;
/// scientific format, precision 8
sci8.scientific().precision(8);
cout << d << ' '
<< gen4(d) << ' '
<< sci8(d) << ' '
<< d << endl;
}
/// scientific format, precision 10
void testsci10(const double& d)
{
/// scientific format, precision 10
Format sci {10, std::ios_base::scientific};
cout << d << ' '
<< gen4(d) << ' '
<< sci(d) << ' '
<< d << endl;
}
|
I seek guidance on how to define the functions declared in the Format class, viz:
1 2 3 4 5 6 7 8 9 10
|
Format& uppercase();
Format& lowercase();
Format& fill(char);
Format& plus(bool b = true); /// explicit plus
/// print trailing zeros
Format& trailing_zeros(bool b = true);
|
I have tried a few things for uppercase(), but they don't work. Hence the query.
Thanks.