NOTE:
These are a little sketchy...I'll fill in details 'soon'.
iomanip
)
precision
/setprecision
fill
/setfill
setf
/setiosflags
and
unsetf
/resetiosflags
(ios_base::XXXX
)
width
/setw
(sets number of characters
next output value should occupy; fills special character if data is too
short; ignored if data is too long)
This should work, but this is sometimes neglected by compiler/library writers. Since we can't depend on setting the width on individual char values, we can resort to something like this:
<< setw(desired_width-1) << "" << character
Note how we set a width one less on a Cstring literal (the empty string) and then print the character. If you wanted it to be left-justified instead, just do this:
<< character << setw(desired_width-1) << ""
Of course, if you are printing a literal character, you could just print it inside a string:
<< setw(desired_width) << "*"
Would left-justify a * in desired_width spaces.
Centering is not provided directly by the stream library. However, we typically do something like this:
<< setw((field_width+item_width)/2) << item
(note the ON-PURPOSE integer division!!).
This simplistic version, however, doesn't take other factors into account:
We can alleviate such concerns via:
<< setw((field_width-item_width)/2) << "" << item
And now all that's really missing is the case where this field is not the last column of a table? We need to fill in after the data like so:
<< setw((field_width-item_width)/2) << "" << item << setw(field_width-item_width-(field_width-item_width)/2) << ""
This will pad afterwards with just the missing spacing.
The main thing missing here is: "How do I know the item_width?" For a char or Cstring, it is pretty simple: 1 or strlen(). But for floating point numbers, you'll have to calculate the number of digits in the number before the decimal point, add one for the decimal point, then add the stream's current precision:
item_width = numdigit(item)+1+os.precision();
(The overload of precision returns the current precision setting of the stream.) For a whole number, simply get the number of digits in the number. Also don't forget to include space for a sign if you are expecting negatives (or if the stream has showpos turned on).
When you are coding a single function or method, it is a good idea to not assume things about the state of a stream either before you started using it or after you are done with it. Try to remember the original values and reset them before you leave:
... function(ostream & os) { // remember old settings -- returned by methods -- as we // set our desired values char old_fill = os.fill('-'); ios_base::fmtflags old_flags = os.setf(ios_base::left|ios_base::showbase); streamsize old_prec = os.precision(4); // do things to stream as needed // replace original settings to wipe out any changes we've // made os.fill(old_fill); os.flags(old_flags); // setf would just | the flags together...leaving ours os.precision(old_prec); return ...; }
The width need not be restored since it lasts for only a single output item, anyway.
(Technically the char for the fill character should be basic_ios::char_type, but unless you are programming internationally, it will end up being whatever char is.) (You did know that char changes from standard ASCII to Extended ASCII to Unicode on various platforms, didn't you? *smile*)
If you are writing output/display methods/functions for an ADT, you can attempt to format as desired by retrieving the stream's current settings and using those to format your overall result. This can be done in many ways. Here's a simplistic example:
void Rational::output(ostream & os) const { streamsize cur_width = os.width(); if (cur_width != 0) // this assumes right justification!!! { short den_len = numdigits(denom); os << setw(cur_width-den_len-1) << numer << '/' << denom; } else // default is as much width as needed { os << numer << '/' << denom; } return; }
But what if the stream is set to left-justify numbers?! We can use some flag manipulation techniques to determine that:
void Rational::output(ostream & os) const { streamsize cur_width = os.width(); if (cur_width != 0) { short len; if ((os.flags() & ios_base::adjustfield) == ios_base::left) { len = numdigits(numer); os << numer << '/' << setw(cur_width-len-1) << denom; } else { len = numdigits(denom); os << setw(cur_width-len-1) << numer << '/' << denom; } } else // default is as much width as needed { os << numer << '/' << denom; } return; }
Here the flags() method returns all the flags at once. We use the bit-wise and to extract the bits for the adjustment flags only (leaving all others 0's). If this is set to left-justification, we print the numerator and slash and justify the denominator. If it is not, we perform as before (justify the numerator and then print the slash and denominator afterwards).
The only question left is what happens if you set a width less than 0?
(Perhaps you should try it out...)
Input Features
dec
, oct
, hex
to avoid the (old) default
input behavior of 'leading 0s mean octal', etc.
setw
on input of a C-string will limit number of characters
read (leaves excess in buffer) to protect the C-string's array
bound limitationsvoid Complex::input(istream & read_from) { char sign; read_from >> real >> sign >> imag; if (sign == '-') { imag = -imag; } while (read_from.good() && // avoid infinite loop if >>'s failed isspace(read_from.peek()) && read_from.peek() != '\n') { read_from.ignore(); } if (!isalpha(read_from.peek())) // no 'i'!! { read_from.clear(ios_base::failbit); // set stream failure } else { read_from >> sign; // re-use local var for 'i' } return; } // later...in the caller... Complex c; cout << "Enter your number: "; c.input(cin); while (cin.fail()) { cin.clear(); cout << "\n\aInvalid format! 'a+bi' required!\n\nAgain: "; c.input(cin); }