|
|
|
9.5 ManipulatorsA manipulator is a function object that can be used as an operand to an input or output operator to manipulate the stream. Manipulators can send additional output to a stream, read input from a stream, set flags, and more. For example, to output a zero-padded, hexadecimal integer, you can use an ostream's member functions or manipulators, whichever you prefer. Example 9-7 shows both ways. Example 9-7. Manipulating an output stream to format a numberusing namespace std;
// Output a value using ostream's member functions.
cout.fill('0');
cout.width(8);
cout.setf(ios_base::internal, ios_base::adjustfield);
cout.setf(ios_base::hex, ios_base::basefield);
cout << value;
// Output the same value using manipulators.
cout << setfill('0') << setw(8) << hex << internal << value;
9.5.1 Standard ManipulatorsThe standard library defines several manipulators for setting formatting flags, setting other formatting parameters, skipping whitespace, flushing output, and more. The following is a list of all the standard manipulators, grouped by header:
Most manipulators are declared in the same header as the stream type they manipulate. The only time you need to #include an additional header is when you use a manipulator that takes an argument. These manipulators are in the <iomanip> header. 9.5.2 Custom ManipulatorsTo write your own manipulator, use the standard manipulators as patterns. The easiest to use are manipulators that take no arguments. A manipulator is simply a function that takes a stream as an argument and returns the same stream. The standard streams overload operator<< and operator>> to take a pointer to such a function as an operand. Suppose you want to write an input manipulator that skips all characters up to and including a newline. (Perhaps this manipulator is used by a command processor after reading a // comment sequence.) Example 9-8 shows one way to write the skipline manipulator. Example 9-8. Skipping a line in an input streamtemplate<typename charT, typename traits>
std::basic_istream<charT,traits>&
skipline(std::basic_istream<charT,traits>& in)
{
charT c;
while (in.get(c) && c != '\n')
;
return in;
}
...
int x;
std::string next;
std::cin >> x >> skipline >> next;
Manipulators that take arguments are harder to write, but only slightly. You need to write some supporting infrastructure, such as additional overloaded operator>> or operator<< functions. For example, suppose you want to parameterize your input skipline manipulator so it skips everything up to a caller-supplied character. This manipulator is defined as a class template, in which the constructor takes the manipulator's argument, that is, the delimiter character. You must overload operator>> so it recognizes your manipulator as an operand and invokes the manipulator's operator( ). You don't need to use operator( ), but this is a good choice when building a reusable infrastructure for manipulators. Example 9-9 shows the new skip manipulator. Example 9-9. Writing a manipulator that takes an argumenttemplate<typename charT>
class skipper
{
public:
typedef charT char_type;
skipper(char_type delim) : delim_(delim) {}
template<typename traits>
void operator( )(std::basic_istream<charT,traits>&) const;
private:
char_type delim_;
};
// Skip the rest of the line. The compiler deduces the traits type from the
// stream argument.
template<typename charT>
template<typename traits>
void skipper<charT>::operator( )(std::basic_istream<charT,traits>& stream)
const
{
char_type c;
while (stream.get(c) && c != delim_)
;
}
// Invoke the skipper manipulator.
template<typename charT, typename traits>
std::basic_istream<charT,traits>&
const skipper<charT>& f)
{
f(stream);
return stream;
}
// Let the compiler deduce the character type.
template<typename charT>
skipper<charT> skip(charT c)
{
return skipper<charT>(c);
}
...
int x;
std::string next;
std::cin >> x >> skip('\n') >> next;
|
|
|
|