| Doc. no. | N2071=06-0141 |
| Date: | 2006-09-09 |
| Project: | Programming Language C++ |
| Reply to: | Martin Sebor |
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.
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.
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:tmbis valid pointer to an object ofstruct tm, andfmtis a valid pointer to an array of typecharTwith length ofchar_traits<charT>(fmt)elements.
Returns: An objectsof unspecified type such that ifinis an object of (derived from)basic_istream<charT, traits>, the type oftmbisstruct tm*and the type offmtisconst charT*then the expressionin >> get_time(tmb, fmt)behaves as iff(str, tmb, fmt)were evaluated wherefmay 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 thein >> sexpression isbasic_istream<charT, traits>&and its value is in.
template <class charT>
smanip put_time (const struct tm *tmb, const charT *fmt);
Returns: An objectsof unspecified type such that ifoutis an object of (derived from)basic_ostream<charT, traits>, the type oftmbisstruct tmb*and the type offmtisconst charT*then the expressionout << sbehaves as iff(s, tmb, fmt)were evaluated wherefmay 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 theout << sexpression isbasic_ostream<charT, traits>&and its value isout.
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.