______________________________________________________________________ 22 Localization library [lib.localization] ______________________________________________________________________ 1 This clause describes components that C++ programs may use to encapsu late (and therefore be largely independent of) cultural differences. The locale facility includes internationalization support for charac ter classification and collation, numeric and currency punctuation, date and time formatting, and message retrieval. 2 The following subclauses describe components for locales, standard facets, and facilities from the ISO C library, as summarized in Table 1: Table 1--Localization library summary +----------------------------------------------------+ | Subclause Header(s) | +----------------------------------------------------+ |_lib.locales_ Locales <locale> | |_lib.std.facets_ Standard locale facets | +----------------------------------------------------+ |_lib.c.locales_ C library locales <clocale> | +----------------------------------------------------+ 22.1 Locales [lib.locales] Header <locale> synopsis #include <limits> #include <string> #include <iosfwd> namespace std { // subclause _lib.locale_, locale: class locale; template <class charT> basic_ostream<charT>& operator<<(basic_ostream<charT>& s, const locale& loc); template <class charT> basic_istream<charT>& operator>>(basic_istream<charT>& s, locale& loc); // subclause _lib.locale.convenience_, convenience interfaces: template <class charT> bool isspace (charT c, const locale& loc) const; template <class charT> bool isprint (charT c, const locale& loc) const; template <class charT> bool iscntrl (charT c, const locale& loc) const; template <class charT> bool isupper (charT c, const locale& loc) const; template <class charT> bool islower (charT c, const locale& loc) const; template <class charT> bool isalpha (charT c, const locale& loc) const; template <class charT> bool isdigit (charT c, const locale& loc) const; template <class charT> bool ispunct (charT c, const locale& loc) const; template <class charT> bool isxdigit(charT c, const locale& loc) const; template <class charT> bool isalnum (charT c, const locale& loc) const; template <class charT> bool isgraph (charT c, const locale& loc) const; template <class charT> charT toupper(charT c, const locale& loc) const; template <class charT> charT tolower(charT c, const locale& loc) const; // subclauses _lib.facet.ctype_ and _lib.facet.ctype.special_, ctype: class ctype_base; template <class charT> class ctype; class ctype<char>; // specialization template <class charT> class ctype_byname; class ctype_byname<char>; // specialization // subclauses _lib.facet.numeric_ and _lib.facet.numpunct_, numeric: template <class charT, class InputIterator> class num_get; template <class charT, class OutputIterator> class num_put; template <class charT> class numpunct; template <class charT> class numpunct_byname; // subclause _lib.facet.collate_, collation: template <class charT> class collate; template <class charT> class collate_byname; // subclause _lib.facet.codecvt_, codeset conversion: class codecvt_base; template <class fromT, class toT, class stateT> class codecvt; template <class fromT, class toT, class stateT> class codecvt_byname; // subclause _lib.facet.date.time_, date and time: class time_base; template <class charT, class InputIterator> class time_get; template <class charT, class InputIterator> class time_get_byname; template <class charT, class OutputIterator> class time_put; template <class charT, class OutputIterator> class time_put_byname; // subclauses _lib.facet.money_ and _lib.facet.moneypunct_, money: class money_base; template <class charT, class InputIterator> class money_get; template <class charT, class OutputIterator> class money_put; template <class charT> class moneypunct; template <class charT> class moneypunct_byname; // subclause _lib.facet.messages_, message retrieval: template <class charT> class messages; template <class charT> class messages_byname; } 1 The header <locale> defines classes and declares functions that encap sulate and manipulate the information peculiar to a locale.1) _________________________ 1) In this subclause, the type name struct tm is an incomplete type that is defined in <ctime>. 22.1.1 Class locale [lib.locale] namespace std { class locale { public: class facet; class id; typedef unsigned category; static const category collate = 0x010, ctype = 0x020, monetary = 0x040, numeric = 0x080, time = 0x100, messages = 0x200, all = 0x3f0; locale(); locale(const locale& other); locale(const char* std_name); locale(const locale& other, const char* std_name, category); template <class Facet> locale(const locale& other, Facet* f); template <class Facet> locale(const locale& other, const locale& one); locale(const locale& other, const locale& one, category); ~locale(); // non-virtual const locale& operator=(const locale& other); template <class Facet> const Facet& use() const; template <class Facet> bool has() const; const basic_string<char>& name() const; bool operator==(const locale& other) const; bool operator!=(const locale& other) const; template <class charT> bool operator()(const basic_string<charT>& s1, const basic_string<charT>& s2) const; static locale global(const locale&); static const locale& classic(); static const locale transparent() }; } 1 A locale constructed from a name string (such as ""), or from parts of two named locales, or read from a stream, has a name; all others do not. Named locales may be compared for equality; an unnamed locale is equal only to (copies of) itself. For an unnamed locale, locale::name() returns the string *. 2 A facet has a dual role: in one sense, it's just a class interface; at the same time, it's an index into a locale's set of facets. Access to the facets of a locale is via two member function templates, locale::use<facet>() and locale::has<facet>(). 3 For example, the standard iostream operator<< might be implemented as: ostream& operator<<(ostream& s, double f) { locale loc = s.rdloc(); if (s.opfx()) { loc.use< num_put<char> >().put(s, s, loc, f); s.osfx(); } return s; } In the call to l.use<...>(), the type argument chooses a facet, making available all members of the named type. If the named facet is not present in a locale (or, failing that, in the global locale), it throws the standard exception bad_cast. You can check if a locale implements a particular facet with the member has<...>(). User- defined facets may be bestowed on a locale, and used the same way as standard facets. 4 All locale semantics are accessed via use<>() and has<>(), with one exception: a member template function operator()(basic_string<T>&, basic_string<T>&) is provided so that a locale may be used as a predi cate argument to the standard collections, to order strings. In addi tion, convenient global interfaces are provided for traditional ctype functions such as isdigit() and isspace(), so that given a locale object loc you can say isspace(c,loc). These are provided to ease the conversion of existing extractors. 5 A locale which does not implement a facet delegates to the global locale. 6 The effect of imbuing on a stream, or installing as the global locale, the result of static member locale::transparent() (or any locale with similar behavior) is undefined. 22.1.1.1 locale types [lib.locale.types] 22.1.1.1.1 Type locale::category [lib.locale.category] typedef unsigned category; Notes: Uses values as defined in <clocale>, e.g. LC_CTYPE. 22.1.1.1.2 Class locale::facet [lib.locale.facet] namespace std { class locale::facet { facet(const facet&); // not defined void operator=(const facet&); // not defined void operator&() {} // not usable protected: facet(size_t refs = 0); virtual ~facet(); }; } 1 Base class for locale feature sets. Any class deriving from facet must declare a static member: static std::locale::id id; 2 For some standard facets there is a `` _byname'' class derived from it that implements POSIX locale semantics; they are specified by name in the standard to allow users to derive from them. If there is no `` _byname'' version, the base class implements POSIX semantics itself, sometimes with the help of another facet. 22.1.1.1.3 Class locale::id [lib.locale.ctype.id] namespace std { class locale::id { void operator=(const id&); // not defined id(const id&); // not defined void operator&() {} // not usable public: id(); }; } 1 Identification of a locale facet interface, used as an index for lookup. 22.1.1.2 locale constructors [lib.locale.cons] locale(); 1 Default constructor: the current global locale. Effects: : imp_(global_ ? global_ : init()) { imp_->add_ref(); } locale(const locale& other); Effects: { imp_ = other.imp_; imp_->add_ref(); } const locale& operator=(const locale& other) const; Effects: if (imp_ != other.imp_) { imp_->rem_ref(); imp_ = other.imp_; imp_->add_ref(); } Returns: *this explicit locale(const char* std_name); Effects: Constructs a locale using standard C locale names, e.g. "POSIX". locale(const locale& other, const char* std_name, category); Effects: Makes a locale composed of `` byname'' facets, and assigns a name. Copies its first argument except for a specified component, which is constructed on the spot. If other has a name, the new locale does also. template <class Facet> locale(const locale& other, Facet* f); 2 To accrete or replace facet Effects: Copies all facets but one from the first argument, installs the other argument as the remaining facet. The resulting locale has no name. : imp_(new imp(*other.imp_, 1)) { f->add_ref(); install(f, Facet::id, "*"); } template <class Facet> locale(const locale& other, const locale& one); 3 To replace a facet Effects: Copies all facets but one from the first argument, and the remaining facet from the second argument. The resulting locale has a no name. : imp_(new imp(*other.imp_, 1)) { facet* f = (Facet*) one.imp_->vec[Facet::id]; // check derivation install(f, Facet::id, merge_names(Facet::id, one.imp_->name_)); } locale(const locale& other, const locale& one, categories); Effects: Copies all facets from the first argument except those that imple ment the specified categories, which are copied from the second argument. The resulting locale has a name only if both locale argu ments have names. 22.1.1.3 locale members [lib.locale.members] 22.1.1.3.1 locale::use [lib.locale.use] template <class Facet> const Facet& use() const; Effects: int i = (const id&) Facet::id; // verify is a locale::id. facet* f = (Facet*) 0; // verify derived from facet. return static_cast<const Facet&>( (i < imp_->vec_.size() && (f = imp_->vec_[i])) ? *f : delegate(i)); Returns: A reference to a facet. If the facet requested is not present in *this, it returns the facet from the current global locale, if pre sent there, or throws an exception. Its result is guaranteed by locale's value semantics to last at least as long as the locale it came from. 22.1.1.3.2 locale::has [lib.locale.has] template <class Facet> bool has() const; Effects: Reports whether a locale implements a particular facet. facet* null = (Facet*) 0; // verify derived from facet. size_t ix = (const id&) Facet::id; // verify is a locale::id. Returns: (ix < imp_->vec_.size()) && imp_->vec_[ix]; 1 If (loc.has<facet>() || locale().has<facet>()) is false, loc.use<facet>() would throw an exception. 22.1.1.3.3 locale::name [lib.locale.name] const basic_string<char>& name() const; Effects: { return imp_->name_; } 22.1.1.4 locale operators [lib.locale.operators] 22.1.1.4.1 locale::operator== [lib.locale.op==] bool operator==(const locale& other) const; Returns: (imp_ == other.imp_) || (name() != "*" && name() == other.name()) 22.1.1.4.2 locale::operator!= [lib.locale.op!=] bool operator!=(const locale& other) const; eturns: !(*this == other) 22.1.1.4.3 locale::operator() [lib.locale.op()] template <class charT> bool operator()(const basic_string<charT>& s1, const basic_string<charT>& s2) const; 1 This template function satisfies requirements for a comparator predi cate template argument (_lib.algorithms_). 22.1.1.4.4 operator<< [lib.locale.op<<] template <class charT> basic_ostream<charT>& operator<<(basic_ostream<charT>& s, const locale& loc) Returns: s << loc.name() << endl 22.1.1.4.5 operator>> [lib.locale.op>>] template <class charT> basic_ostream<charT>& operator>>(basic_ostream<charT>& s, locale& loc) Effects: Read a line, construct a locale, throw exception if cannot. 22.1.1.5 locale static members [lib.locale.statics] 22.1.1.5.1 locale::global [lib.locale.global] static locale global(const locale&); 1 Replaces ::setlocale(...). 22.1.1.5.2 locale::classic [lib.locale.classic] static const locale& classic(); 1 The locale. 22.1.1.5.3 locale::transparent [lib.locale.transparent] static const locale transparent(); 1 Continuously updated global locale. Returns: locale(new imp(1, 0, true)) 22.1.2 Convenience interfaces [lib.locale.convenience] 22.1.2.1 Character classification [lib.classification] 22.1.2.1.1 isspace [lib.locale.isspace] template <class charT> bool isspace(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::space, c). 22.1.2.1.2 isprint [lib.locale.isprint] template <class charT> bool isprint(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::print, c). 22.1.2.1.3 iscntrl [lib.locale.iscntrl] template <class charT> bool iscntrl(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::cntrl, c). 22.1.2.1.4 isupper [lib.locale.isupper] template <class charT> bool isupper(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::upper, c). 22.1.2.1.5 islower [lib.locale.islower] template <class charT> bool islower(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::lower, c). 22.1.2.1.6 isalpha [lib.locale.isalpha] template <class charT> bool isalpha(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::alpha, c). 22.1.2.1.7 isdigit [lib.locale.isdigit] template <class charT> bool isdigit(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::digit, c). 22.1.2.1.8 ispunct [lib.locale.ispunct] template <class charT> bool ispunct(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::punct, c). 22.1.2.1.9 isxdigit [lib.locale.isxdigit] template <class charT> bool isxdigit(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::xdigit, c). 22.1.2.1.10 isalnum [lib.locale.isalnum] template <class charT> bool isalnum(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::alnum, c). 22.1.2.1.11 isgraph [lib.locale.isgraph] template <class charT> bool isgraph(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().is(ctype<charT>::graph, c). 22.1.2.2 Character conversiona [lib.conversions] 22.1.2.2.1 toupper [lib.locale.toupper] template <class charT> charT toupper(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().toupper(c). 22.1.2.2.2 tolower [lib.locale.tolower] template <class charT> charT tolower(charT c, const locale& loc) const; Returns: loc.use<ctype<charT> >().tolower(c). 22.2 Standard locale facets [lib.std.facets] 22.2.1 The ctype facet [lib.facet.ctype] namespace std { struct ctype_base { enum ctype_mask { space=1<<0, print=1<<1, cntrl=1<<2, upper=1<<3, lower=1<<4, alpha=1<<5, digit=1<<6, punct=1<<7, xdigit=1<<8, alnum=(1<<5)|(1<<6), graph=(1<<7)|(1<<6)|(1<<5) }; }; +------- BEGIN BOX 1 -------+ ISSUE: should this be in the global namespace? +------- END BOX 1 -------+ ctype_base::ctype_mask operator|(ctype_base::ctype_mask a, ctype_base::ctype_mask b); { return (ctype_base::ctype_mask)(unsigned(a)|unsigned(b)); } template <class charT> class ctype; template <class charT> class ctype_byname } 22.2.1.1 Template class ctype [lib.locale.ctype] template <class charT> class ctype : public locale::facet, public ctype_base { public: typedef charT char_type; protected: virtual bool do_is(ctype_mask mask, charT c) const; virtual const charT* do_is(const charT* low, const charT* high, ctype_mask* vec) const; virtual const char* do_scan_is(ctype_mask mask, const charT* low, const charT* high) const; virtual const char* do_scan_not(ctype_mask mask, const charT* low, const charT* high) const; virtual charT do_toupper(charT) const; virtual const charT* do_toupper(charT* low, const charT* high) const; virtual charT do_tolower(charT) const; virtual const charT* do_tolower(charT* low, const charT* high) const; virtual charT do_widen(char) const; virtual const char* do_widen(const char* lo, const char* hi, charT* dest) const; virtual char do_narrow(charT, char dfault) const; virtual const charT* do_narrow(const charT* lo, const charT* hi, char dfault, char* dest) const; public: bool is(ctype_mask mask, charT c) const; const charT* is(const charT* low, const charT* high, ctype_mask* vec) const; const charT* scan_is(ctype_mask mask, const charT* low, const charT* high) const; const charT* scan_not(ctype_mask mask, const charT* low, const charT* high) const; charT toupper(charT) const; const charT* toupper(charT* low, const charT* high) const; charT tolower(charT c) const; const charT* tolower(charT* low, const charT* high) const; charT widen(char c) const; const char* widen(const char* lo, const char* hi, charT* to) const; char narrow(charT c, char dfault) const; const charT* narrow(const charT* lo, const charT*, char dfault, char* to) const; static locale::id id; ctype(size_t refs = 0); protected: ~ctype(); }; 1 Class ctype encapsulates the C library <cctype> features. istream members are required to use ctype<> for character classing. 22.2.1.2 ctype members [lib.locale.ctype.members] 1 Most of these functions are +------- BEGIN BOX 2 -------+ To Be Specified +------- END BOX 2 -------+ 22.2.1.2.1 do_is [lib.locale.ctype::do.is] virtual bool do_is(ctype_mask mask, charT c) const; virtual const charT* do_is(const charT* low, const charT* high, ctype_mask* vec) const; 22.2.1.2.2 do_scan_is [lib.locale.ctype::do.scan.is] virtual const char* do_scan_is(ctype_mask mask, const charT* low, const charT* high) const; 22.2.1.2.3 do_scan_not [lib.locale.ctype::do.scan.not] virtual const char* do_scan_not(ctype_mask mask, const charT* low, const charT* high) const; 22.2.1.2.4 do_toupper [lib.locale.ctype::do.toupper] virtual charT do_toupper(charT) const; virtual const charT* do_toupper(charT* low, const charT* high) const; 22.2.1.2.5 do_tolower [lib.locale.ctype::do.tolower] virtual charT do_tolower(charT) const; virtual const charT* do_tolower(charT* low, const charT* high) const; 22.2.1.2.6 do_widen [lib.locale.ctype::do.widen] virtual charT do_widen(char) const; virtual const char* do_widen(const char* lo, const char* hi, charT* dest) const; 22.2.1.2.7 do_narrow [lib.locale.ctype::do.narrow] virtual char do_narrow(charT, char dfault) const; virtual const charT* do_narrow(const charT* lo, const charT* hi, char dfault, char* dest) const; 22.2.1.2.8 is [lib.locale.ctype::is] bool is(ctype_mask mask, charT c) const; const charT* is(const charT* low, const charT* high, ctype_mask* vec) const; Returns: do_is(mask,c) or do_is(low,high,vec) 22.2.1.2.9 scan_is [lib.locale.ctype::scan.is] const charT* scan_is(ctype_mask mask, const charT* low, const charT* high) const; Returns: do_scan_is(masklow,high) 22.2.1.2.10 scan_not [lib.locale.ctype::scan.not] const charT* scan_not(ctype_mask mask, const charT* low, const charT* high) const; Returns: do_scan_not(mask,low,high) 22.2.1.2.11 toupper [lib.locale.ctype::toupper] charT toupper(charT) const; const charT* toupper(charT* low, const charT* high) const; Returns: do_toupper(c) or do_toupper(low,high) 22.2.1.2.12 tolower [lib.locale.ctype::tolower] charT tolower(charT c) const; const charT* tolower(charT* low, const charT* high) const; Returns: do_tolower(c) or do_tolower(low,high) 22.2.1.2.13 widen [lib.locale.ctype::widen] charT widen(char c) const; const char* widen(const char* lo, const char* hi, charT* to) const; Returns: do_widen(c) or do_widen(lo,hi,to) 22.2.1.2.14 narrow [lib.locale.ctype::narrow] char narrow(charT c, char dfault) const; const charT* narrow(const charT* lo, const charT*, char dfault, char* to) const; Returns: do_narrow(c,dfault) or do_narrow(lo,hi,dfault,to) 22.2.1.2.15 ctype constructor [lib.locale.ctype::cons] ctype(size_t refs = 0); Effects: : locale::facet(refs) {} 22.2.1.3 Template class ctype_byname [lib.locale.ctype.byname] template <class charT> class ctype_byname : public ctype<charT> { // this class is specialized by vendors for char and wchar_t. protected: virtual char do_toupper(char) const; virtual const char* do_toupper(char* low, const char* high) const; virtual char do_tolower(char) const; virtual const char* do_tolower(char* low, const char* high) const; public: ctype_byname(const char*, size_t refs = 0); protected: ~ctype_byname(); }; } 22.2.2 ctype specializations [lib.facet.ctype.special] namespace std { class ctype<char> : public locale::facet, public ctype_base { public: typedef char char_type; protected: const ctype_mask* const table_; static const ctype_mask classic_table_[numeric_limits<unsigned char>::max()+1]; virtual char do_toupper(char) const; virtual const char* do_toupper(char* low, const char* high) const; virtual char do_tolower(char) const; virtual const char* do_tolower(char* low, const char* high) const; public: bool is(ctype_mask mask, char c) const; const char* is(const char* lo, const char* hi, ctype_mask* vec) const; const char* scan_is(ctype_mask mask, const char* low, const char* high) const; const char* scan_not(ctype_mask mask, const char* low, const char* high) const; char toupper(char c) const; const char* toupper(char* low, const char* high) const; char tolower(char c) const; const char* tolower(char* low, const char* high) const; char widen(char c) const; const char* widen(const char* lo, const char* hi, char* to) const; char narrow(char c, char /*dfault*/) const; const char* narrow(const char* lo, const char* hi, char /*dfault*/, char* to) const; static locale::id id; ctype(const ctype_mask* tab = 0, bool del = false, size_t refs = 0); protected: ~ctype(); }; } 1 A specialization ctype<char> is provided, so that the member functions on type char may be implemented inline. Definitions of these func tions have been provided for exposition. Only the char, and not the unsigned char and signed char forms, has been provided. The special ization is specified in the standard (and not left as an implementa tion detail) because it affects the derivation interface for ctype<char>. 22.2.3 ctype<char> members [lib.facet.ctype.char.members] 22.2.3.1 is [lib.ctype.char::is] bool is(ctype_mask mask, char c) const; Returns: table_[(unsigned char)c] & mask const char* is(const char* lo, const char* hi, ctype_mask* vec) const; Effects: while (lo != hi) *vec++ = table_[(unsigned char)*lo++]; return lo; 22.2.3.2 scan_is [lib.ctype.char::scan.is] const char* scan_is(ctype_mask mask, const char* low, onst char* high) const; Effects: while (low != high && !(table_[(unsigned char) *low] & mask)) { ++low; } return low; 22.2.3.3 scan_not [lib.ctype.char::scan.not] const char* scan_not(ctype_mask mask, const char* low, const char* high) const; Effects: while (low != high && (table_[(unsigned char)*low] & mask)) { ++low; } return low; 22.2.3.4 toupper [lib.ctype.char::toupper] char toupper(char c) const; const char* toupper(char* low, const char* high) const; Returns: do_toupper(c) or do_toupper(low,high) 22.2.3.5 tolower [lib.ctype.char::tolower] char tolower(char c) const; const char* tolower(char* low, const char* high) const; Returns: do_tolower(c) or do_tolower(low,high) 22.2.3.6 widen [lib.ctype.char::widen] char widen(char c) const; const char* widen(const char* lo, const char* hi, char* to) const; Returns: or memcpy(to, lo, hi-lo); return hi 22.2.3.7 narrow [lib.ctype.char::narrow] char narrow(char c, char /*dfault*/) const; const char* narrow(const char* lo, const char* hi, char /*dfault*/, char* to) const; Returns: c or memcpy(to, lo, hi-lo); return hi; 22.2.3.8 ctype<char> [lib.ctype.char::ctor] ctype(const ctype_mask* tab = 0, bool del = false, size_t refs = 0); Effects: : locale::facet(refs), table_(tab ? tab : classic_table_), delete_it_(tab ? del : false) {} 22.2.3.9 ctype<char> destructor [lib.ctype.char::dtor] ~ctype(); Effects: if (delete_it_) delete table_; 22.2.4 The numeric facet [lib.facet.numeric] 22.2.4.1 Template class num_get [lib.locale.num.get] namespace std { template <class charT, class InputIterator = istreambuf_iterator<charT> > class num_get : public locale::facet { public: typedef charT char_type; typedef InputIterator iter_type; typedef basic_ios<charT> ios; protected: virtual iter_type do_get(iter_type, ios&, const locale&, bool& v) const; virtual iter_type do_get(iter_type, ios&, const locale&, long& v) const; virtual iter_type do_get(iter_type, ios&, const locale&, unsigned long& v) const; // virtual iter_type do_get(iter_type, ios&, const locale&, // long long& v) const; virtual iter_type do_get(iter_type, ios&, const locale&, double& v) const; virtual iter_type do_get(iter_type, ios&, const locale&, long double& v) const; public: iter_type get(iter_type s, ios& f, const locale&, bool& v) const; iter_type get(iter_type s, ios& f, const locale&, long& v) const; iter_type get(iter_type s, ios& f, const locale&, unsigned long& v) const; // iter_type get(iter_type s, ios& f, const locale&, long long& v) const; iter_type get(iter_type s, ios& f, const locale&, double& v) const; iter_type get(iter_type s, ios& f, const locale&, long double& v) const; static locale::id id; num_get(size_t refs = 0); protected: ~num_get(); }; } 1 The classes num_get<> and num_put<> handle numeric formatting and parsing. Virtual functions are provided for several numeric types; implementations are allowed to delegate conversion of smaller types to extractors for larger ones, but are not required to. The functions take a locale argument because their base class implementation refers to numpunct features, which identify preferred numeric punctuation. Extractors and inserters for the standard iostreams are required to call num_get and num_put member functions. The ios& argument is used both for format control and to report errors. 2 Members of num_get take a locale argument because they may need to refer to the locale's numpunct facet. 22.2.4.2 Template class num_put [lib.locale.num.put] namespace std { template <class charT, class OutputIterator = ostreambuf_iterator<charT> > class num_put : public locale::facet { public: typedef charT char_type; typedef OutputIterator iter_type; typedef basic_ios<charT> ios; protected: virtual iter_type do_put(iter_type, ios&, const locale&, bool v) const; virtual iter_type do_put(iter_type, ios&, const locale&, long v) const; virtual iter_type do_put(iter_type, ios&, const locale&, unsigned long) const; //virtual iter_type do_put(iter_type, ios&, const locale&, long long v) const; virtual iter_type do_put(iter_type, ios&, const locale&, double v) const; virtual iter_type do_put(iter_type, ios&, const locale&, long double v) const; public: iter_type put(iter_type s, ios& f, const locale& loc, bool v5) const; iter_type put(iter_type s, ios& f, const locale& loc, long v) const; iter_type put(iter_type s, ios& f, const locale& loc, unsigned long v) const; // iter_type put(iter_type s, ios& f, const locale& loc, long long v) const; iter_type put(iter_type s, ios& f, const locale& loc, double v) const; iter_type put(iter_type s, ios& f, const locale& loc, long double v) const; static locale::id id; num_put(size_t refs = 0); protected: ~num_put(); }; } 1 Members of num_put take a locale argument because they may need to refer to the locale's numpunct facet. The ios& argument is used for formatting reference only and error reporting. 22.2.5 The numeric punctuation facet [lib.facet.numpunct] 22.2.5.1 Template class numpunct [lib.locale.numpunct] namespace std { template <class charT> class numpunct : public locale::facet { public: typedef charT char_type; typedef basic_string<charT> string; protected: virtual string do_decimal_point() const; virtual string do_thousands_sep() const; virtual vector<char> do_grouping() const; virtual string do_truename() const; // for bool virtual string do_falsename() const; // for bool public: string decimal_point() const { return do_decimal_point(); } string thousands_sep() const { return do_thousands_sep(); } vector<char> grouping() const { return do_grouping(); } string truename() const { return do_truename(); } string falsename() const { return do_falsename(); } static locale::id id; numpunct(size_t refs = 0); protected: ~numpunct(); }; } 1 numpunct<> specifies numeric punctuation. The base class provides classic numeric formats, while the _byname version supports general POSIX numeric formatting semantics. 22.2.5.2 Template class [lib.locale.numpunct.byname] numpunct_byname namespace std { template <class charT> class numpunct_byname : public numpunct<charT> { // this class is specialized by vendors for char and wchar_t. protected: virtual string do_decimal_point() const; virtual string do_thousands_sep() const; virtual vector<char> do_grouping() const; virtual string do_truename() const; // for bool virtual string do_falsename() const; // for bool public: numpunct_byname(const char*, size_t refs = 0); protected: ~numpunct_byname(); }; } 1 numpunct is used by num_get and num_put facets. 22.2.6 The collation facet [lib.facet.collate] 22.2.6.1 Template class collate [lib.locale.collate] namespace std { template <class charT> class collate : public locale::facet { public: typedef charT char_type; typedef basic_string<charT> string; protected: virtual int do_compare(const char* low1, const char* high1, const char* low2, const char* high2) const; virtual string do_transform(const char* low, const char* high) const; virtual long do_hash( const char* low, const char* high) const; public: int compare(const char* low1, const char* high1, const char* low2, const char* high2) const; { return do_compare(low1, hight1, low2, high2); } string transform(const char* low, const char* high) const; { return do_transform(low, high); } long hash(const char* low, const char* high) const; { return do_hash(low, high); } static locale::id id; collate(size_t refs = 0); protected: ~collate(); }; } 1 The class collate<charT> provides features for use in the collation of strings. A locale member function template, operator(), uses the col late facet to allow a locale to act directly as the predicate argument for algorithms. The base class uses lexicographic ordering. 2 locale.use<collate>() is used for string comparisons. 22.2.6.2 collate members [lib.locale.collate.members] 22.2.6.2.1 compare [lib.collate::compare] int compare(const char* low1, const char* high1, const char* low2, const char* high2) const; Returns: do_compare(low1, hight1, low2, high2) 22.2.6.2.2 transform [lib.collate::transform] string transform(const char* low, const char* high) const; Returns: do_transform(low, high) 22.2.6.2.3 hash [lib.collate::hash] long hash(const char* low, const char* high) const; Returns: do_hash(low, high) 22.2.6.3 Template class [lib.locale.collate.byname] collate_byname namespace std { template <class charT> class collate_byname : public collate<charT> { // this class is specialized by vendors for char and wchar_t. protected: virtual int do_compare(const char* low1, const char* high1, const char* low2, const char* high2) const; virtual string do_transform(const char* low, const char* high) const; virtual long do_hash( const char* low, const char* high) const; public: collate_byname(const char*); protected: ~collate_byname(); }; // this template function satisfies requirements for a // comparator predicate template argument: template <class charT> bool locale::operator()(const basic_string<charT>& s1, const basic_string<charT>& s2); } 22.2.6.4 collate_byname [lib.locale.collate.byname.members] members 22.2.6.4.1 operator() [lib.collate::op.paren] bool locale::operator()(const basic_string<charT>& s1, const basic_string<charT>& s2); Returns: use< collate<charT> >().compare(s1.begin(), s1.end(), s2.begin(), s2.end()) < 0; 22.2.7 The codeset conversion facet [lib.facet.codecvt] 22.2.7.1 Template class codecvt [lib.locale.codecvt] namespace std { struct codecvt_base { enum result { ok, partial, error }; }; template <class fromT, class toT, class stateT> class codecvt : public locale::facet, public codecvt_base { public: typedef fromT from_type; typedef toT to_type; typedef stateT state_type; protected: virtual result do_convert(stateT& state, const fromT* from, const fromT* from_end, const fromT*& from_next, toT* to, toT* to_limit, toT*& to_next) const; public: result convert(stateT& state, const fromT* from, const fromT* from_end, const fromT*& from_next, toT* to, toT* to_limit, toT*& to_next) const; static locale::id id; codecvt(size_t refs = 0) protected: ~codecvt() {} }; } 1 The class codecvt<fromT,toT,stateT> is for use when converting from one codeset to another, such as from wide characters to multibyte characters, or between wide character sets such as Unicode and EUC. Instances of this facet are typically used in pairs. 2 Its only member function, convert(), returns an enumeration value which indicates whether it completed the conversion ( ok), ran out of space in the destination ( partial), or encountered a from_type char acter it could not convert ( error). 3 In all cases it leaves the from_next and to_next pointers pointing one beyond the last character successfully converted. 4 The stateT argument selects the pair of codesets being mapped between. Base class members are pure virtual. 5 Implementations are obliged to provide specializations for <char,wchar_t,mbstate_t> and <wchar_t,char,mbstate_t>. 22.2.7.2 codecvt members [lib.locale.codecvt.members] 22.2.7.2.1 convert [lib.codecvt::convert] result convert(stateT& state, const fromT* from, const fromT* from_end, const fromT*& from_next, toT* to, toT* to_limit, toT*& to_next) const; Returns: do_convert(state, from, from_end, from_next, to, to_limit, to_next); 22.2.7.3 Template class [lib.locale.codecvt.byname] codecvt_byname namespace std { template <class fromT, class toT, class stateT> class codecvt_byname : public codecvt<fromT, toT, stateT> { protected: virtual result do_convert(stateT& state, const fromT* from, const fromT* from_end, const fromT*& from_next, toT* to, toT* to_limit, toT*& to_next) const; public: codecvt_byname(const char*, size_t refs = 0); protected: ~codecvt_byname(); }; } 22.2.8 The date and time facet [lib.facet.date.time] 1 The classes time_get<charT> and time_put<charT> provide date and time formatting and parsing. The time formatting function put() takes an extra format argument to accommodate the POSIX strftime() extensions. The ios& argument is used for format control and to report errors. 22.2.8.1 Template class time_get [lib.locale.time.get] namespace std { struct time_base { enum dateorder { no_order, dmy, mdy, ymd, ydm }; }; template <class charT, class InputIterator = istreambuf_iterator<charT> > class time_get : public locale::facet, public time_base { public: typedef charT char_type; typedef InputIterator iter_type; typedef basic_ios<charT> ios; protected: virtual dateorder do_date_order() const; virtual iter_type do_get_time(iter_type s, ios&, const locale&, tm* t) const; virtual iter_type do_get_date(iter_type s, ios&, const locale&, tm* t) const; virtual iter_type do_get_weekday(iter_type s, ios&, const locale&, tm* t) const; virtual iter_type do_get_monthname(iter_type s, ios&, const locale&, tm* t) const; virtual iter_type do_get_year(iter_type s, ios&, const locale&, tm* t) const; public: dateorder date_order() const { return do_date_order(); } iter_type get_time(iter_type s, ios& f, const locale& loc, tm* tfP) const; iter_type get_date(iter_type s, ios& f, const locale& loc, tm* tfP) const; iter_type get_weekday(iter_type s, ios& f, const locale& loc, tm* t ) const; iter_type get_monthname(iter_type s, ios& f, const locale& loc, tm* 6t) const; iter_type get_year(iter_type s, ios& f, const locale& loc, tm* t) const; static locale::id id; time_get(size_t refs = 0); protected: ~time_get(); }; } 22.2.8.2 Template class [lib.locale.time.get.byname] time_get_byname namespace std { template <class charT, class InputIterator = istreambuf_iterator<charT> > class time_get_byname : public time_get<charT, InputIterator> { protected: virtual dateorder do_date_order() const; virtual iter_type do_get_time(iter_type s, ios&, const locale&, tm* t) const; virtual iter_type do_get_date(iter_type s, ios&, const locale&, tm* t) const; virtual iter_type do_get_weekday(iter_type s, ios&, const locale&, tm* t) const; virtual iter_type do_get_monthname(iter_type s, ios&, const locale&, tm* t) const; virtual iter_type do_get_year(iter_type s, ios&, const locale&, tm* t) const; public: time_get_byname(const char*, size_t refs = 0); protected: ~time_get_byname(); }; } 22.2.8.3 Template class time_put [lib.locale.time.put] namespace std { template <class charT, class OutputIterator = ostreambuf_iterator<charT> > class time_put : public locale::facet { public: typedef charT char_type; typedef OutputIterator iter_type; typedef basic_ios<charT> ios; protected: virtual iter_type do_put(iter_type s, ios&, const locale&, const tm* t, char format, char modifier) const; public: // the following is implemented in terms of other member functions. iter_type put(iter_type s, ios& f, struct tm const* tmb, const charT* pattern, const charT* pat_end) const; iter_type put(iter_type s, ios& f, const locale& loc, struct tm const* Pt, char format, char modifier = ' ') const; static locale::id id; time_put(size_t refs = 0); protected: ~time_put(); }; } 22.2.8.4 Template class [lib.locale.time.put.byname] time_put_byname namespace std { template <class charT, class OutputIterator = ostreambuf_iterator<charT> > class time_put_byname : public time_put<charT, OutputIterator> { protected: virtual iter_type do_put(iter_type s, ios&, const locale&, const tm* t, char format, char modifier) const; public: time_put_byname(const char*, size_t refs = 0); protected: ~time_put_byname(); }; } 22.2.9 The money facet [lib.facet.money] 1 These handle money formats. A template parameter indicates whether local or international monetary formats are to be used. money_get<> and money_put<> use moneypunct<> features if appropriate. money punct<> provides basic format information for money processing. The ios& argument is used for format control and to report errors. 22.2.9.1 Template class money_get [lib.locale.money.get] namespace std { template <class charT, bool Intl = false, class InputIterator = istreambuf_iterator<charT> > class money_get : public locale::facet { typedef charT char_type; typedef InputIterator iter_type; typedef basic_string<charT> string; typedef basic_ios<charT> ios; protected: virtual iter_type do_get(iter_type, ios&, const locale&, double& units) const; virtual iter_type do_get(iter_type, ios&, const locale&, string& digits) const; public: iter_type get(iter_type s, ios& f, const locale& loc, double& units ) const; iter_type get(iter_type s, ios& f, const locale& loc, string& digit s) const; static const bool intl = Intl; static locale::id id; money_get(size_t refs = 0); protected: ~money_get(); }; } 22.2.9.2 Template class money_put [lib.locale.money.put] namespce std { template <class charT, bool Intl = false, class OutputIterator = ostreambuf_iterator<charT> > class money_put : public locale::facet { public: typedef charT char_type; typedef OutputIterator iter_type; typedef basic_string<charT> string; typedef basic_ios<charT> ios; protected: virtual iter_type do_put(iter_type, ios&, const locale&, double units) const; virtual iter_type do_put(iter_type, ios&, const locale&, const string& digits) const; public: iter_type put(iter_type s, ios& f, const locale& loc, double units&) const; iter_type put(iter_type s, ios& f, const locale& loc, const string& 6dgts) const; static const bool intl = Intl; static locale::id id; money_put(size_t refs = 0); protected: ~money_put(); }; } 22.2.10 The money punctuation facet [lib.facet.moneypunct] 22.2.10.1 Template class moneypunct [lib.locale.moneypunct] namespace std { struct money_base { enum part { symbol='$', sign='=', space=' ', value='v', none=0 }; struct pattern { char field[4]; }; }; template <class charT, bool International = false> class moneypunct : public locale::facet, public money_base { public: typedef charT char_type; static const bool intl = International; typedef basic_string<charT> string; protected: virtual charT do_decimal_point() const; virtual charT do_thousands_sep() const; virtual vector<char> do_grouping() const; virtual string do_curr_symbol() const; virtual string do_positive_sign() const; virtual string do_negative_sign() const; virtual int do_frac_digits() const; virtual pattern do_pos_format() const; virtual pattern do_neg_format() const; public: charT decimal_point() const { return do_decimal_point(); } charT thousands_sep() const { return do_thousands_sep(); } vector<char> grouping() const { return do_grouping(); } string curr_symbol() const { return do_curr_symbol(); }; string positive_sign() const { return do_positive_sign; } string negative_sign() const { return do_negative_sign; } int frac_digits() const { return do_frac_digits(); } pattern pos_format() const { return do_pos_format(); } pattern neg_format() const { return do_neg_format(); } static locale::id id; moneypunct(size_t refs = 0); protected: ~moneypunct() {} }; } 1 This provides money punctuation, similar to numpunct above. 22.2.10.2 Template class [lib.locale.moneypunct.byname] moneypunct_byname namespace std { template <class charT, bool Intl = false> class moneypunct_byname : public moneypunct<charT, Intl> { protected: virtual charT do_decimal_point() const; virtual charT do_thousands_sep() const; virtual vector<char> do_grouping() const; virtual string do_curr_symbol() const; virtual string do_positive_sign() const; virtual string do_negative_sign() const; virtual int do_frac_digits() const; virtual pattern do_pos_format() const; virtual pattern do_neg_format() const; public: moneypunct_byname(const char*, size_t refs = 0); protected: ~moneypunct_byname(); }; } 22.2.11 The message retrieval facet [lib.facet.messages] 1 Class messages<charT> implements POSIX message retrieval.2) 22.2.11.1 Template class messages [lib.locale.messages] namespace std { template <class charT> class messages : public locale::facet { public: typedef charT char_type; typedef int catalog; typedef basic_string<charT> string; protected: virtual catalog do_open(const string&, const locale&) const; virtual string do_get(catalog, int set, int msgid, const string& dfault) const; virtual void do_close(catalog) const; public: catalog open(const string& fn, const locale& l) const { return do_open(fn, l); } string get(catalog c, int set, int msgid, const string& dfault) const; void close(catalog c) const; static locale::id id; messages(size_t refs = 0); protected: ~messages(); }; } 22.2.11.2 Tmessages members [lib.locale.messages.members] 22.2.11.3 Template class [lib.locale.messages.byname] messages_byname namespace std { template <class charT> class messages_byname : public messages<charT> { protected: virtual catalog do_open(const string&, const locale&) const; virtual string do_get(catalog, int set, int msgid, const string& dfault) const; virtual void do_close(catalog) const; public: messages_byname(const char*, size_t refs = 0); protected: ~messages_byname(); }; } _________________________ 2) It should be flexible enough to retrieve messages from X, MS Win dows, or Macintosh resource files as well. 22.2.12 User-defined facets [lib.facets.examples] 1 A user-defined facet may be added to a locale and used identically as the built-in facets. To create a new facet interface users simply derive, from locale::facet, a class containing a static member: static locale::id id;. (The locale member function templates verify its type and storage class.) 2 For those curious about the mechanics: this initializa tion/identification system depends only on the initialization to 0 of static objects, before static constructors are called. When an instance of a facet is installed in a locale, the locale checks whether an id has been assigned, and if not, assigns one. Before this occurs, any attempted use of its interface causes the bad_cast excep tion to be thrown. 3 Here is a program that just calls C functions: #include <locale> extern "C" void c_function(); int main() { using namespace std; locale::global(locale("")); // same as setlocale(LC_ALL, ""); c_function(); return 0; } 4 In other words, C library localization is unaffected. 5 Traditional global localization is still easy: #include <iostream> #include <locale> int main(int argc, char** argv) { using namespace std; locale::global(locale("")); // set the global locale cin.imbue(locale()); // imbue it on the std streams cout.imbue(locale()); cerr.imbue(locale()); return MyObject(argc, argv).doit(); } 6 Greater flexibility is possible: #include <iostream> #include <locale> int main() { using namespace std; cin.imbue(locale("")); // the user's preferred locale cout.imbue(locale::classic()); double f; while (cin >> f) cout << f << endl; return (cin.fail() != 0); } 7 In a European locale, with input 3.456,78, output is 3456.78. This can be important even for simple programs, which may need to write a data file in a fixed format, regardless of a user's preference. 8 For example: // file: Date.h #include <locale> ... class Date { ... public: Date(unsigned day, unsigned month, unsigned year); std::string asString(const std::locale& = std::locale()); }; istream& operator>>(istream& s, Date& d); ostream& operator<<(ostream& s, Date d); ... 9 This example illustrates two architectural uses of class locale. The first is as a default argument in Date::asString(), where the default is the global (presumably user-preferred) locale. The second is in the operators << and >>, where a locale ``hitchhikes'' on another object, in this case a stream, to the point where it is needed. // file: Date.C #include <Date> #include <stringstream> std::string Date::asString(const std::locale& l) { using namespace std; stringstream s; s.imbue(l); s << *this; return s.data(); } std::istream& operator>>(std::istream& s, Date& d) { using namespace std; if (!s.ipfx(0)) return s; locale loc = s.rdloc(); struct tm t; loc.use<time_get<char> >().get_date(s, s, loc, &t); if (s) d = Date(t.tm_day, t.tm_mon + 1, t.tm_year + 1900); s.isfx(); return s; } 10A locale object may be extended with a new facet simply by construct ing it with an instance of a class derived from locale::facet. The only member you must define is the static member id, which identifies your class interface as a new facet. For example, imagine we want to classify Japanese characters: // file: jctype.h #include <locale> namespace My { using namespace std; class JCtype : public locale::facet { public: static locale::id id; // required for use as a new locale facet bool is_kanji(wchar_t c); JCtype() {} protected: ~JCtype() {} }; } // file: filt.C #include <iostream> #include <locale> #include <jctype> // above std::locale::id JCtype::id; // the static JCtype member declared above. int main() { using namespace std; typedef ctype<wchar_t> ctype; locale loc(locale(""), // the user's preferred locale ... new My::JCType); // and a new feature ... wchar_t c = loc.use<ctype>().widen('!'); if (loc.use<My::JCType>().is_kanji(c)) cout << "no it isn't!" << endl; return 0; } 11The new facet is used exactly like the built-in facets. 12Replacing an existing facet is even easier. Here we do not define a member id because we are reusing the numpunct<charT> facet interface: // my_bool.C #include <iostream> #include <locale> #include <string> namespace My { using namespace std; typedef numpunct_byname<char> numpunct; class BoolNames : public numpunct { typedef basic_string<char> string; protected: string do_truename() { return "Oui Oui!"; } string do_falsename() { return "Mais Non!"; } ~BoolNames() {} public: BoolNames(const char* name) : numpunct(name) {} }; } int main(int argc, char** argv) { using namespace std; // make the user's preferred locale, except for... locale loc(locale(""), new My::BoolNames("")); cout.imbue(loc); cout << "Any arguments today? " << (argc > 1) << endl; return 0; } 22.3 C Library Locales [lib.c.locales] 1 Header <clocale> (Table 2): Table 2--Header <clocale> synopsis +------------------------------------------------+ | Type Name(s) | +------------------------------------------------+ |Macros: | | LC_MONETARY LC_NUMERIC LC_TIME | +------------------------------------------------+ |Struct: lconv | +------------------------------------------------+ |Functions: localeconv setlocale | +------------------------------------------------+ 2 The contents are the same as the Standard C library. SEE ALSO: ISO C subclause 7.10.4.