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:

    template<class charT, class Traits>
    std::basic_istream<charT, Traits>&
    operator >> (std::basic_istream<charT, Traits >& is, date& dat)
    {
     std::ios_base::iostate err = 0;

     std::use_facet<std::time_get<charT,Traits> >                 //1
       (is.getloc())
       .get_date(is, std::istreambuf_iterator<charT,Traits>(),    //2
                 is, err, &dat.tm_date);                          //3

     return is;
    }

`//1` | Use 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.).
`//2` | The 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.
`//3` | The 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:

    template<class charT, class Traits>
    std::basic_ostream<charT, Traits>& operator <<
     (std::basic_ostream<charT, Traits >& os, const date& dat)
    {
     std::use_facet
      <std::time_put<charT,ostreambuf_iterator<charT,Traits> > > //1
       os.getloc())
       .put(os,os,os.fill(),&dat.tm_date,'x');                    //2
     return os;
    }

`//1` | Here we use the `time_put` facet of the stream's locale to handle formatting of dates.
`//2` | The 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.