1) hex is not operating on the parameter 10. <<
operators associate left-to-right, which means your code is the same as:
(mystream<<hex)<<10;
So your overload has to return an object which, when 10 is shifted into it, prints in hex (or if not prints, writes data somewhere). As everyone says, this is done by saving flags in the stream object itself, then returning *this
. The reason flags are used is precisely because the "10" is not available yet, since the second <<
has not been evaluated yet. The first <<
operator call cannot print anything - it just has to get ready for when the second one is called.
2) hex is a function. It can be compared with other functions:
ostream &operator<<(ostream &s, ios_base& (*m)(ios_base &)) {
if (m == hex) {
} else if (m == oct) {
} else if (m == dec) {
}
}
Except you don't normally want to do that, you want the default behaviour, which is something like:
ostream &operator<<(ostream &s, ios_base& (*m)(ios_base &)) {
return m(s);
}
(I may be wrong on that, I've never looked at the implementation, but the general idea is that the operator calls the manipulator function, and the manipulator (the clue's in the name) manipulates the stream).
std::hex
sets the std::ios::hex
format flag on its parameter. Then in your operator<<(int)
override, if you have one, check the format flags by calling flags()
.
3) Manipulators which take paramers are functions too, but their return types are unspecified, meaning it's up to the implementation. Looking at my gcc iomanip
header, setw
returns _Setw
, setprecision
returns _Setprecision
, and so on. The Apache library does it differently, more like the no-args manipulators. The only thing you can portably do with parameterized manipulators is apply them to an iostream with operator<<
, they have no defined member functions or operators of their own.
So just like hex
, to handle setw
you should inherit from std::ios_base
, rely on the operator<<
implementation provided by your library, then when you come to format your data, examine your own width, precision, etc, using the width()
, precision()
, etc, functions on ios_base
.
That said, if for some bizarre reason you needed to intercept the standard operator<<
for these manipulators, you could probably bodge something together, along these lines:
template <typename SManip>
mystream &operator<<(mystream &s, SManip m) {
stringstream ss;
// set the state of ss to match that of s
ss.width(s.width());
ss.precision(s.precision());
// etc
ss << m;
// set the state of s to match that of ss
s.width(ss.width());
s.precision(ss.precision());
// etc
return s;
}
I do consider this a bodge, though. You're not really supposed to interfere with stream manipulators, just let your base class do the work and look up the results.