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:tmb
is valid pointer to an object ofstruct tm
, andfmt
is a valid pointer to an array of typecharT
with length ofchar_traits<charT>(fmt)
elements.
Returns: An objects
of unspecified type such that ifin
is an object of (derived from)basic_istream<charT, traits>
, the type oftmb
isstruct tm*
and the type offmt
isconst charT*
then the expressionin >> get_time(tmb, fmt)
behaves as iff(str, tmb, fmt)
were evaluated wheref
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 thein >> s
expression isbasic_istream<charT, traits>&
and its value is in.
template <class charT>
smanip put_time (const struct tm *tmb, const charT *fmt);
Returns: An objects
of unspecified type such that ifout
is an object of (derived from)basic_ostream<charT, traits>
, the type oftmb
isstruct tmb*
and the type offmt
isconst charT*
then the expressionout << s
behaves as iff(s, tmb, fmt)
were evaluated wheref
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 theout << s
expression 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.