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> basic_istream<charT, Traits>& operator >> (basic_istream<charT, Traits >& is, date& dat) { ios_base::iostate err = 0; use_facet<time_get<charT,Traits> >(is.getloc()) //1 .get_date(is, istreambuf_iterator<charT,Traits>() //2 ,is, err, &dat.tm_date); //3 return is; }
//1 | Use the 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() function. Its time_get facet is accessed through a call to the global use_facet<..>() function. 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 the section on stream buffer iterators in the Standard C++ Library User's Guide.) Following the philosophy of iterators in the Standard C++ 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 istreambuf_iterator class 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 class 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 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 has to be a pointer to an object of type 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> basic_ostream<charT, Traits>& operator << (basic_ostream<charT, Traits >& os, const date& dat) { use_facet <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 output stream to an ostreambuf_iterator. This way the output will be 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 will be 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 will explain how you can improve and complete your inserter or extractor if it directly uses low-level components like locales or stream buffers.
©Copyright 1998, Rogue Wave Software, Inc.
Send mail to report errors or comment on the documentation.