//: C04:Manips.cpp
// Format.cpp using manipulators
#include
#include
#include
using namespace std;
int main() {
ofstream trc("trace.out");
int i = 47;
float f = 2300114.414159;
char* s = "Is there any more?";
trc << setiosflags(ios::unitbuf
| ios::showbase | ios::uppercase
| ios::showpos);
trc << i << endl;
trc << hex << i << endl
<< oct << i << endl;
trc.setf(ios::left, ios::adjustfield);
trc << resetiosflags(ios::showbase)
<< dec << setfill('0');
trc << "fill char: " << trc.fill() << endl;
trc << setw(10) << i << endl;
trc.setf(ios::right, ios::adjustfield);
trc << setw(10) << i << endl;
trc.setf(ios::internal, ios::adjustfield);
trc << setw(10) << i << endl;
trc << i << endl; // Without setw(10)
trc << resetiosflags(ios::showpos)
<< setiosflags(ios::showpoint)
<< "prec = " << trc.precision() << endl;
trc.setf(ios::scientific, ios::floatfield);
trc << f << resetiosflags(ios::uppercase) << endl;
trc.setf(ios::fixed, ios::floatfield);
trc << f << endl;
trc << f << endl;
trc << setprecision(20);
trc << "prec = " << trc.precision() << endl;
trc << f << endl;
trc.setf(ios::scientific, ios::floatfield);
trc << f << endl;
trc.setf(ios::fixed, ios::floatfield);
trc << f << endl;
trc << f << endl;
trc << setw(10) << s << endl;
trc << setw(40) << s << endl;
trc.setf(ios::left, ios::adjustfield);
trc << setw(40) << s << endl;
} ///:~
You can see that a lot of the multiple statements have been condensed into a single chained insertion. Notice the call to setiosflags( )in which the bitwise-OR of the flags is passed. This could also have been done with setf( )and unsetf( )as in the previous example .
When using setw( )with an output stream, the output expression is formatted into a temporary string that is padded with the current fill character if needed, as determined by comparing the length of the formatted result to the argument of setw( ). In other words, setw( )affects the result string of a formatted output operation. Likewise, using setw( )with input streams only is meaningful when reading strings , as the following example makes clear.
//: C04:InputWidth.cpp
// Shows limitations of setw with input
#include
#include
#include
#include
#include
#include
using namespace std;
int main() {
istringstream is("one 2.34 five");
string temp;
is >> setw(2) >> temp;
assert(temp == "on");
is >> setw(2) >> temp;
assert(temp == "e");
double x;
is >> setw(2) >> x;
double relerr = fabs(x - 2.34) / x;
assert(relerr <= numeric_limits::epsilon());
} ///:~
If you attempt to read a string, setw( )will control the number of characters extracted quite nicely… up to a point. The first extraction gets two characters, but the second only gets one, even though we asked for two. That is because operator>>( )uses white space as a delimiter (unless you turn off the skipwsflag). When trying to read a number, however, such as x, you cannot use setw( )to limit the characters read. With input streams, use only setw( )for extracting strings .
Sometimes you’d like to create your own manipulators, and it turns out to be remarkably simple. A zero-argument manipulator such as endlis simply a function that takes as its argument an ostreamreference and returns an ostreamreference. The declaration for endlis .
ostream& endl(ostream&);
Now, when you say: .
cout << "howdy" << endl;
the endlproduces the address of that function. So the compiler asks, "Is there a function I can call that takes the address of a function as its argument?" Predefined functions in do this; they’re called applicators (because they apply a function to a stream). The applicator calls its function argument, passing it the ostreamobject as its argument. You don’t need to know how applicators work to create your own manipulator; you only need to know that they exist. Nonetheless, they’re simple. Here’s the (simplified) code for an ostreamapplicator:
ostream& ostream::operator<<(ostream& (*pf)(ostream&)) {
return pf(*this);
}
The actual definition is a little more complicated since it involves templates, but this code illustrates the technique. When a function such as *pf(that takes a stream parameter and returns a stream reference) is inserted into a stream, this applicator function is called, which in turn executes the function to which pfpoints. Applicators for ios_base, basic_ios, basic_ostream, and basic_istreamare predefined in the standard C++ library .
To illustrate the process, here’s a trivial example that creates a manipulator called nlthat is equivalent to just inserting a newline into a stream (i.e., no flushing of the stream occurs, as with endl): .
//: C04:nl.cpp
// Creating a manipulator
#include
using namespace std;
ostream& nl(ostream& os) {
return os << '\n';
}
int main() {
cout << "newlines" << nl << "between" << nl
<< "each" << nl << "word" << nl;
} ///:~
When you insert nlinto an output stream, such as cout, the following sequence of calls ensues:
cout.operator<<(nl) è nl(cout)
The expression
os << '\n';
inside nl( )calls ostream::operator(char), which of course returns the stream, which is what is ultimately returned from nl( ). [45] Before putting nl into a header file, make it an inline function (see Chapter 7).
As you’ve seen, zero-argument manipulators are easy to create. But what if you want to create a manipulator that takes arguments? If you inspect the header, you’ll see a type called smanip, which is what the manipulators with arguments return. You might be tempted to somehow use that type to define your own manipulators, but don’t give in to the temptation. The smaniptype is implementation-dependent, so using it would not be portable. Fortunately, you can define such manipulators in a straightforward way without any special machinery, based on a technique introduced by Jerry Schwarz, called an effector . [46] Jerry Schwarz is the designer of iostreams.
An effector is a simple class whose constructor formats a string representing the desired operation, along with an overloaded operator<<to insert that string into a stream. Here’s an example with two effectors. The first outputs a truncated character string, and the second prints a number in binary .
Читать дальше