Doc. no. N2071=06-0141
Date: 2006-09-09
Project: Programming Language C++
Reply to: Martin Sebor

Iostream manipulators for convenient extraction and insertion of struct tm objects

Index

Motivation

The C++ standard library facet class templates provide a robust interface to the localization library, one that lends itself well to being implemented and used with efficiency in mind. The get and put parsing and formatting facets specifically are especially well suited to be used as the engine of a higher-level and more convenient interfaces such as iostreams. However, due to the large number and complexity of their arguments and due to the complexities of the error handling involved they are less than ideal for direct use by programs.

The num_get and num_put facets are a good example of where this design works well and does not pose any serious problems to programs. Nearly every C++ program relies on the services provided by the facets by virtue of making calls to the arithmetic iostream extractor and inserter operators, yet only very few programs ever need to access these facets directly. In fact, many C++ programmers are not even aware that the facets exist.

Unfortunately, the num_get and num_put facets mentioned above are the only such example in the C++ localization library. No convenient interface similar to the arithmetic inserters and extractors exists to make it as easy to parse or format time (or monetary) sequences and values, respectively, as it is for arithmetic types. C++ programs that need to do so must code directly to the low-level interfaces of the time and monetary get and put facets. We believe that these interfaces, while powerful, are cumbersome enough to use that they deter most C++ programmers from taking advantage of their functionality.

Rather than dealing with the intricacies of the time_put facet, C++ programmers typically resort to using the C standard library function strftime which provides a convenient interface familiar to anyone who has ever used printf.

In POSIX environments, C++ programmers in need of parsing time sequences can make use of the strftime counterpart, strptime. In others, however, they have no alternative but to turn to non-portable solutions or implement their own.

Description

In this paper we propose a convenient interface to the parsing and formatting facilities provided by the time_get and time_put facets, one that we believe is nearly as easy to use as the arithmetic inserters and extractors. The proposed interface takes the form of a pair of matching manipulators that, when used with the existing extraction and insertion operators, provide the desired simplicity and ease of use. Note that due to the wide variety of formats simply overloading the extractor and inserter operators on struct tm would not be practical.

Note that the definition of function f shown in the Proposed Changes section relies on the extension proposed in N2070=06-0140. However, it may be possible to implement the manipulators even without this extension, for example by relying on implementation details.

Note: While independent of one another, this proposal should be reviewed and considered in conjunction with N2071=06-0140 – Iostream manipulators for convenient extraction and insertion of monetary values.

Proposed Changes

Add a new section after lib.std.manip titled Extended Manipulators [lib.ext.manip], with the following text:

The header <iomanip> also defines a number of functions that use the smanip type to provide extractors and inserters that allow for the extraction and parsing of time sequences and values, respectively.
The type designated smanip in each of the following function descriptions is implementation-defined and may be different for each function.
template <class charT> smanip get_time (struct tm *tmb, const charT *fmt);
Requires:tmb is valid pointer to an object of struct tm, and fmt is a valid pointer to an array of type charT with length of char_traits<charT>(fmt) elements.
Returns: An object s of unspecified type such that if in is an object of (derived from) basic_istream<charT, traits>, the type of tmb is struct tm* and the type of fmt is const charT* then the expression in >> get_time(tmb, fmt) behaves as if f(str, tmb, fmt) were evaluated where f may be defined similarly to the following (exception handling omitted):
        template <class charT, class traits>
        void f (basic_ios<charT, traits>& str, struct tm *tmb, const charT *fmt)
        {
            typedef streambuf_iterator<charT> Iter;
            typedef time_get<charT, Iter>     TimeGet;

            ios_base::iostate err = ios_base::goodbit;
            const TimeGet &tg = use_facet<TimeGet>(strm.getloc ());

            tg.get (Iter (str.rdbuf ()), Iter (), str, err, tmb, fmt, fmt + traits::length (fmt));

            if (ios_base::goodbit != err)
                str.setstate (err);
        }
        
Note: The type of the in >> s expression is basic_istream<charT, traits>& and its value is in.
template <class charT> smanip put_time (const struct tm *tmb, const charT *fmt);
Returns: An object s of unspecified type such that if out is an object of (derived from) basic_ostream<charT, traits>, the type of tmb is struct tmb* and the type of fmt is const charT* then the expression out << s behaves as if f(s, tmb, fmt) were evaluated where f may be defined similarly to the following (exception handling omitted):
        template <class charT, class traits>
        void f (basic_ios<charT, traits>& str, const struct tm *tmb, const charT *fmt)
        {
            typedef ostreambuf_iterator<charT> Iter;
            typedef time_put<charT, Iter>      TimePut;

            const TimePut &tp = use_facet<TimePut>(str.getloc ());
            const Iter end = tp.put (Iter (str.rdbuf ()), str, str.fill (), tmb, fmt, fmt + traits::length (fmt));

            if (end.failed ())
                str.setstate (ios_base::badbit);
        }
        
Note: The type of the out << s expression is basic_ostream<charT, traits>& and its value is out.

Implementation

A reference implementation of this extension is available for review in the Open Source Apache C++ Standard Library in the form of a complete example program.