iostream examples

User defined extraction operators

Creating extractors for classes is similar to creating inserters. The Pair extractor could be defined thus:

   istream& operator>>(istream& i, Pair& pair)
   	return i >> pair.x >> pair.y ;
By convention, an extractor converts characters from its first (istream&) argument, stores the result in its second (reference) argument, and returns its first argument. Making the second argument a reference is essential because the purpose of an extractor is to store a new value in the second argument.

A subtle point is the propagation of errors by extractors. By convention, an extractor whose first argument has a non-zero error state will not extract any more characters from the istream and will not clear bits in the error state, but it is allowed to set previously unset error bits. Further, an extractor that fails for some reason must set at least one error bit. The code in the Pair extractor does nothing explicitly to respect these conventions, but because the only way it modifies i is with extractors that honor the conventions, the conventions will be respected.

Conventions also apply to the meaning of the individual error bits. In particular ios::failbit indicates that some problem was encountered while getting characters from the ultimate producer, while ios::badbit means that the characters read from the stream did not conform to the expectation of the extractor. For example, suppose that the components of a Pair are supposed to be non-zero. The above definition might become:

   istream& operator>>(istream& i, Pair& pair)
   	i >> pair.x >> pair.y ;
   	if ( !i ) return i ;
   	if ( pair.x == 0 || pair.y == 0 ) {
   		i.clear(ios::badbit|i->rdstate()) ;
   	return i ;

This uses the (misleadingly named) clear() member function to set the error state to indicate that the extractor found incorrect data. Oring ios::badbit with i->rdstate() (the current state) preserves any bits that may previously have been set.

The Pair extractor has been defined so that it can input values that were output by the Pair inserter. Maintaining this symmetry is an important general principle that is worth some effort.

The next example is the Vec extractor, which will require an opening [ followed by a sequence of numbers, followed by a ]. Recall that the Vec inserter uses , as a separator and does not insert any whitespace between numbers. The extractor must accept such input. It will also accept slightly more general formats. In particular it allows extra whitespace, and it allows any visible character to be used as a separator. It also deals properly with a variety of special conditions such as errors in the input format.

   istream& operator>>(iostream& i, Vec& v)
   	int n = 0 ;		// number of elements
   	char delim ;

v.resize(n) ;

// verify opening prefix i >> delim ; if ( delim != '[' ) ; i.putback(delim); i.clear(ios::badbit|i.rdstate()) ; return i ; } if ( i.flags() & ios::skipws ) i >> ws ; if ( i.peek() == ']' ) return i ;

// loop while ( i && delim != ']' ) { v.resize(++n) ; i >> v[n-1] >> delim ; }

return i ; }

The steps this code performs are:
Next topic: char* extractor
Previous topic: Input

© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 27 April 2004