Previous fileTop of DocumentContentsIndex pageNext file
Apache C++ Standard Library User's Guide

32.4 Improved Extractors and Inserters

The format of dates depends on local and cultural conventions. Naturally, we want our extractor and inserter to parse and format the date according to such conventions. To add this functionality to them, we use the time facet contained in the respective stream's locale as follows:

//1Use the std::time_get facet of the input stream's locale to handle parsing of dates according to cultural conventions defined by the locale. The locale in question is obtained through the stream's getloc() member function. Its std::time_get facet is accessed through a call to the function template std::use_facet<...>(). The type argument to the use_facet() function template is the facet type. (See the chapter on internationalization for more details on locales and facets.).
//2The facet's member function get_date() is called. It takes a number of arguments, including:

A range of input iterators. For the sake of performance and efficiency, facets directly operate on a stream's buffer. They access the stream buffer through stream buffer iterators. (See Chapter 43, "Stream Iterators.") Following the philosophy of iterators in the C++ Standard Library, we must provide a range of iterators. The range extends from the iterator pointing to the first character to be accessed, to the character past the last character to be accessed (the past-the-end-position).

The beginning of the input sequence is provided as a reference to the stream. The std::istreambuf_iterator class template has a constructor taking a reference to an input stream. Therefore, the reference to the stream is automatically converted into an istreambuf_iterator that points to the current position in the stream. As end of the input sequence, an end-of-stream iterator is provided. It is created by the default constructor of istreambuf_iterator. With these two stream buffer iterators, the input is parsed from the current position in the input stream until a date or an invalid character is found, or the end of the input stream is reached.
//3The other parameters are:

Formatting flags. A reference to the ios_base part of the stream object is provided here, so that the facet can use the stream's formatting information through the stream's members flags(), precision(), and width().

An iostream state. It is used for reporting errors while parsing the date.

A pointer to a time object. It must be a pointer to an object of type std::tm, which is the time structure defined by the C library. Our date class maintains such a time structure, so we hand over a pointer to the respective data member tm_date.

The inserter is built analogously:

//1Here we use the time_put facet of the stream's locale to handle formatting of dates.
//2The facet's put() function takes the following arguments:

An output iterator. We use the automatic conversion from a reference to an object of type ostreambuf_iterator<charT,Traits>. This way the output is inserted into the output stream, starting at the current write position.

The formatting flags. Again we provide a reference to the ios_base part of the stream to be used by the facet for retrieving the stream's formatting information.

The fill character. We would use the stream's fill character here. Naturally, we could use any other fill character; however, the stream's settings are normally preferred.

A pointer to a time structure. This structure is filled with the result of the parsing.

A format specifier. This can be a character, like 'x' in our example here, or alternatively, a character sequence containing format specifiers, each consisting of a % followed by a character. An example of such a format specifier string is "%A, %B %d, %Y". It has the same effect as the format specifiers for the strftime() function in the C library; it produces a date like: Tuesday, June 11, 1996. We don't use a format specifier string here, but simply the character 'x', which specifies that the locale's appropriate date representation shall be used.

Note how these versions of the inserter and extractor differ from previous simple versions: we no longer rely on existing inserters and extractors for built-in types, as we did when we used operator<<(int) to insert the date object's data members individually. Instead, we use a low-level service like the time facet's get_date() service. The consequence is that we give away all the functionality that high-level services like the inserters and extractors already provide, such as format control, error handling, etc.

The same happens if you decide to access the stream's buffer directly, perhaps for optimizing your program's runtime efficiency. The stream buffer's services, too, are low-level services that leave to you the tasks of format control, error handling, etc.

In the following sections, we explain how you can improve and complete your inserter or extractor if it directly uses low-level components like locales or stream buffers.

Previous fileTop of DocumentContentsIndex pageNext file