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

Iostream manipulators for convenient extraction and insertion of monetary values

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 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 monetary (or time) 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 monetary and time 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.

Description

In this paper we propose a convenient interface to the parsing and formatting facilities provided by the money_get and money_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 the manipulator approach was chosen since the extraction and insertion operators are already overloaded on both types commonly used to represent monetary values, that is long double and basic_string.

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 struct tm objects.

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 monetary 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 moneyT> smanip get_money (moneyT& mon, bool intl = false);
Requires: The type moneyT is either long double or a specialization of basic_string<charT, char_traits<charT>, allocator<charT>> on a valid character type charT.
Returns: An object s of unspecified type such that if in is an object of (derived from) basic_istream<charT, traits> and the type of mon is moneyT then the expression in >> get_money(mon, intl) behaves as if f(str, mon, intl) were evaluated where f may be defined similarly to the following (exception handling omitted):
        template <class charT, class traits, class moneyT>
        void f (basic_ios<charT, traits>& str, moneyT& mon, bool intl)
        {
            typedef istreambuf_iterator<charT> Iter;
            typedef money_get<charT, Iter>     MoneyGet;

            ios_base::iostate err = ios_base::goodbit;
            const MoneyGet &mg = use_facet<MoneyGet>(str.getloc ());

            mg.get (Iter (str.rdbuf ()), Iter (), intl, strm, err, mon);

            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, class moneyT> smanip put_money (const moneyT& mon, bool intl = false);
Requires: The type moneyT is either long double or a specialization of basic_string<charT, char_traits<charT>, allocator<charT>> on a valid character type charT.
Returns: An object s of unspecified type such that if out is an object of (derived from) basic_ostream<charT, traits>, the type of mon is moneyT and the type of intl is bool then the expression out << s behaves as if f(s, mon, intl) were evaluated where f may be defined similarly to the following (exception handling omitted):
        template <class charT, class traits, class moneyT>
        void f (basic_ios<charT, traits>& str, const moneyT& mon, bool intl)
        {
            typedef ostreambuf_iterator<charT> Iter;
            typedef money_put<charT, Iter>     MoneyPut;

            const MoneyPut &mp = use_facet<MoneyPut>(str.getloc ());
            const Iter end = tp.put (Iter (str.rdbuf ()), intl, str, str.fill (), mon);

            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.