16.3.2 Manipulators
As we could see, format flags are not particularly convenient. There is, however, a more „user friendly” mechanism of formatting data — the so called manipulators. These are basically functions defined in ios class and invoked by their names given as elements to be inserted to or extracted from a stream. As a result of their invocation, format flags can (although do not have to) be modified.
Actually, as we will see, manipulators do not have to be implemented as functions — they usually correspond to what is known as function objects, to be discussed in section on object functions .
There are tow kinds of manipulators: with and without parameters.
16.3.2.1 Parameterless manipulators
Parameterless manipulators are put into a stream without parentheses — just their names. There are quite a few such manipulators — their names correspond to the names of flags discussed in section on flags .
hex, oct, dec — set the base of integral numbers to be output, as does an invocation of the method setf(ios::hex,ios::basefield) etc. Modification of format flag is persistent, to change it, one has to use another manipulator or call setf again.
left, right, internal — set the way data is justified within its field, as does the method setf(ios::left,ios::adjustfield) etc.
fixed, scientific — they set the format for floating-point numbers, as does setf(ios::fixed,ios::floatfield) etc.
showbase, noshowbase — they act as invocation of the methods setf(ios::showbase) and setf(ios::noshowbase).
endl — sends line termination character to output stream and flushes it, so all characters are immediately output to the destination of the stream (screen, file etc).
P123: mani.cpp Parameterless manipulators
1. #include <iostream> 2. using namespace std; 3. 4. int main() { 5. int a = 0xdf, b = 0771, c = 123; 6. 7. cout << "dec (default): " 8. << dec << a << " " << b << " " << c << endl; 9. 10. cout << "hex, no showbase: " 11. << hex << a << " " << b << " " << c << endl; 12. 13. cout.setf(ios::showbase); 14. 15. cout << "hex, with showbase: " 16. << a << " " << b << " " << c << endl; 17. 18. cout << "oct, with showbase: " 19. << oct << a << " " << b << " " << c << endl; 20. 21. cout.unsetf(ios::showbase); 22. 23. cout << "oct, no showbase: " 24. << a << " " << b << " " << c << endl; 25. }
dec (default): 223 505 123 hex, no showbase: df 1f9 7b hex, with showbase: 0xdf 0x1f9 0x7b oct, withWe do not specify a base on line 15, as it has already been set as hex on line 11. We have to set it again only if we want to change it, e.g., for oct, as we do on line 19.
It is relatively easy to define our own parameterless manipulator. In order to do it, we have to define a function with one parameter of type 'reference to a stream' and returning by reference exactly the same stream; e.g.,
ostream& my_manip(ostream& stream) { // ... return stream; }When such a function is defined, we can use our manipulator just by inserting its name, without any arguments or parentheses, into a stream. The function will be invoked automatically with the current stream as an argument. It will return a reference to the stream, so the manipulator may be followed by another stream extraction or insertion operator, whichever is appropriate for the stream.
P124: wmani.cpp User defined manipulators
1. #include <iostream> 2. using namespace std; 3. 4. ostream& scient(ostream&); 5. ostream& normal(ostream&); 6. ostream& acomma(ostream&); 7. 8. int main() { 9. double x = 123.456; 10. cout << scient << x << acomma 11. << normal << x << endl; 12. } 13. 14. ostream& scient(ostream& str) { 15. str.setf(ios::showpos | ios::showpoint); 16. str.setf(ios::scientific, ios::floatfield); 17. str.precision(12); 18. return str; 19. } 20. 21. ostream& normal(ostream& str) { 22. str.flags((ios::fmtflags)0); 23. return str; 24. } 25. 26. ostream& acomma(ostream& str) { 27. return str << ", "; 28. }
+1.234560000000e+02, 123.456The first manipulator, scient, defined on lines 14-19, using methods already known to us, modifies format flag of the stream. The second,normal, restores default settings for the format flag; they correspond to the value of the format flag equal to zero of type ios::fmtflags — that is why we used casting on line 22. Finally, the third manipulator, acomma, does not modify any flags — it just inserts a comma and a space into the stream.
The parameter of the function defining a manipulator is in all cases of type ostream&. This makes the construct quite flexible: an argument does not have to be cout, it could be a reference to any object of type ostream or any type derived form ostream, e.g., an object of typeofstream representing an output stream connected to a file.
16.3.2.2 Manipulators with arguments
There are also manipulators with parameters. They are used in the same way as parameterless manipulators, but they require an argument (or arguments) to be specified (in parentheses, as in a function invocation). Usually, they are implemented as function objects (see section on function objects ).
Manipulators with parameters are accessible after including the header iomanip.
Several manipulators with parameters are already predefined; they perform the same tasks that the methods that we have already described, the main difference being the fact that they return, as all manipulators do, a reference to the stream they are inserted into.
setw(int wid) — sets the field width for the next I/O operation, as the method width(int), that we have already described. The method returns old setting of the field width; the manipulator, as always, returns a reference to the stream. Both set the minimum value of field width — if this is not enough to represent a given piece of data, the field width will be expanded. Default value is 0, what means „as wide as needed, but no wider”.
setfill(int padd) — sets padding character that is used to fill unused space when the field width is wider than the width of data to be output (space character by deault). Corresponds to the method fill.
setiosflags(ios::fmtflags flag) — modifies format flag, as one-argument method setf, i.e., „ORs” flag with the current format flag.
P125: primatr.cpp Formatting
1. #include <iostream> 2. #include <iomanip> 3. using namespace std; 4. 5. void printMatrix(ostream&,double**,int,int,const char*); 6. 7. int main() { 8. const int DIM = 5; 9. double t[][DIM] = { { 1, 3, 5, 23, 16.42}, 10. {4.567, 4, 6, 234.345, 98}, 11. { 585, 34, 1, 67, 31.2}, 12. { 1, 0, 1, 2345.967, 123.2}, 13. { 1.2, 10, 34.1, 5.900, 0.2} 14. }; 15. double* tab[DIM]; 16. for (int i = 0; i < 5; i++) tab[i] = t[i]; 17. 18. char name[5]; 19. int prec = 3; 20. 21. cout << "Name: "; 22. cin >> setw(5) >> name; 23. 24. printMatrix(cout, tab, DIM, prec, name); 25. } 26. 27. void printMatrix(ostream& strm, double* tab[], int size, 28. int prec, const char* name) { 29. ios::fmtflags old = 30. strm.setf(ios::fixed, ios::floatfield); 31. 32. strm << setiosflags(strm.flags() | ios::showpoint) 33. << setprecision(prec) << "\nMatrix: " << name 34. << "\n\n"; 35. 36. for (int i = 0; i < size; i++) { 37. strm << "ROW " << setfill('0') << setw(2) 38. << (i+1) << ":" << setfill(' '); 39. for (int j = 0; j < size; j++) 40. strm << setw(9) << tab[i][j]; 41. strm << endl; 42. } 43. strm << endl << setiosflags(old); 44. }
Note also the way the program reads a name from the user (line 22). As the array which stores the name is only 5 characters long, we usesetw to limit the length of a C-string which can be read: even if the user enters a longer name, it will be trucated (to four characters + NUL), but no overflow of the array will occur:
Name: zanzibar Matrix: zanz ROW 01: 1.000 3.000 5.000 23.000 16.420 ROW 02: 4.567 4.000 6.000 234.345 98.000 ROW 03: 585.000 34.000 1.000 67.000 31.200 ROW 04: 1.000 0.000 1.000 2345.967 123.200 ROW 05: 1.200 10.000 34.100 5.900 0.200
Another important issue is avoiding side effects when calling a function. That is why our function, before returning, restores the format flag to the state it was on entry (lines 29 and 43).
It is possible to define our own manipulators with parameters, but it is more complicated than it was for parameterless manipulators; we will come back to this issue in section on function objects .
No comments:
Post a Comment