______________________________________________________________________ 22 Localization library [lib.localization] ______________________________________________________________________ 1 This clause describes components that C++ programs may use to perform localization of strings. The locale facility includes international ization support for character classification and collation, numeric and currency punctuation, date and time formatting, and message retrieval. 2 The following subclauses describe components for locales (_lib.locales_), standard facets (_lib.std.facets_), and facilities included from the ISO C library (_lib.c.locales_). 22.1 Locales [lib.locales] 1 Headers: --<locale> 2 Table 1: Table 1--Header <locale> synopsis +--------------------------------------------------------------------------+ | Type Name(s) | +--------------------------------------------------------------------------+ |Template classes: | |locale::codecvt locale::msg | |locale::codecvt_byname locale::msg_byname | |locale::collate locale::numpunct | |locale::collate_byname locale::num_get | |locale::ctype locale::num_put | |locale::ctype_byname locale::time_get | |locale::moneypunct locale::time_get_byname | |locale::moneypunct_byname locale::time_put | |locale::money_get locale::time_put_byname | |locale::money_put | +--------------------------------------------------------------------------+ |Classes: locale locale::ctype<char> | +--------------------------------------------------------------------------+ |Struct: locale::ctype_base | +--------------------------------------------------------------------------+ |Operator functions: operator<< (locale) operator>> (locale) | +--------------------------------------------------------------------------+ 3 The header <locale> defines classes and several functions that encap sulate and manipulate the information peculiar to a locale.1) 22.1.1 Class locale [lib.locale] class locale { public: class id; class facet; class ctype_base; template <class charT> class ctype; class ctype<char>; // specialization template <class charT> class ctype_byname; class ctype_byname<char>; // specialization 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; template <class charT> class collate; template <class charT> class collate_byname; template <class fromT, class toT, class stateT> class codecvt; template <class fromT, class toT, class stateT> class codecvt_byname; 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; 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; template <class charT> class msg; template <class charT> class msg_byname; // member function template use<Facet>() returns a reference to // a facet. Its result is guaranteed by locale's value semantics // to last at least as long as the locale it came from. If the // facet requested is not present in *this, it returns the facet // from the current global locale, if present, or throws an exception. template <class Facet> const Facet& use() const { 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)); } _________________________ 1) In this subclause, the type name struct tm is an incomplete type that is defined in <ctime>. // has<Facet>() simply reports whether a locale implements a particular // facet. If (loc.has<facet>() || locale().has<facet>()) is false, // loc.use<facet>() would throw an exception. template <class Facet> bool has() const { facet* null = (Facet*) 0; // verify derived from facet. size_t ix = (const id&) Facet::id; // verify is a locale::id. return (ix < imp_->vec_.size()) && imp_->vec_[ix]; } const basic_string<char>& name() const { return imp_->name_; } bool operator==(const locale& other) const { return ((imp_ == other.imp_) || (name() != "*" && name() == other.name())) } bool operator!=(const locale& other) const { return !(*this == other); } // convenience interfaces template <class charT> inline bool isspace(charT c) const; template <class charT> inline bool isprint(charT c) const; template <class charT> inline bool iscntrl(charT c) const; template <class charT> inline bool isupper(charT c) const; template <class charT> inline bool islower(charT c) const; template <class charT> inline bool isalpha(charT c) const; template <class charT> inline bool isdigit(charT c) const; template <class charT> inline bool ispunct(charT c) const; template <class charT> inline bool isxdigit(charT c) const; template <class charT> inline bool isalnum(charT c) const; template <class charT> inline bool isgraph(charT c) const; template <class charT> inline charT toupper(charT c) const; template <class charT> inline charT tolower(charT c) const; // this template function satisfies requirements for a // comparator predicate template argument template <class charT> inline bool operator()(const basic_string<charT>& s1, const basic_string<charT>& s2) const; //********** constructors **************** // default constructor: the current global locale locale() : imp_(global_ ? global_ : init()) { imp_->add_ref(); } locale(const locale& other) { imp_ = other.imp_; imp_->add_ref(); } const locale& operator=(const locale& other) const { if (imp_ != other.imp_) { imp_->rem_ref(); imp_ = other.imp_; imp_->add_ref(); } return *this; } // the following constructor makes a locale composed of "byname" // facets, and assigns a name. locale(const char* std_name); // using std C locale names, e.g. "POSIX" typedef unsigned category; // as defined in <clocale>, e.g. LC_CTYPE // the following constructor 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. locale(const locale& other, const char* std_name, category); // the following constructor copies all facets but one from the first // argument, installs the other argument as the remaining facet. // The resulting locale has no name. template <class Facet> locale(const locale& other, Facet* f) // to accrete or replace facet : imp_(new imp(*other.imp_, 1)) { f->add_ref(); install(f, Facet::id, "*"); } // the following constructor copies all facets but one from the // first argument, and the remaining facet from the second argument. // The resulting locale has a name only if both argument locales do. template <class Facet> locale(const locale& other, const locale& one) // to replace a facet : 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() { imp_->rem_ref(); } // non-virtual // static members: static locale global(const locale&); // replaces ::setlocale(...) static const locale& classic(); // the "C" locale static const locale transparent() // continuously updated global locale { return locale(new imp(1, 0, true)); } }; template <class charT> basic_ostream<charT>& operator<<(basic_ostream<charT>& s, const locale& l) { s << l.name() << endl; return s;} template <class charT> basic_istream<charT>& operator>>(basic_istream<charT>& s, locale& l); // read a line, construct a locale, throw exception if cannot. 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 l = s.rdloc(); if (s.opfx()) { l.use< locale::num_put<char> >().put(s, s, l, 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 two exceptions. Convenient interfaces are provided for traditional ctype functions such as isdigit() and isspace(), so that given a locale object loc you can say loc.isspace(c). These are provided to ease the conversion of existing extractors. Also, a member template function operator()(basic_string<T>&, basic_string<T>&) is provided so that a locale may be used as a predicate argument to the standard collec tions. 5 The static member locale::global(), which returned a snapshot of the current global locale, is replaced by the default constructor locale(), which is both shorter to type and useful in more places. The static member locale::transparent(), and any locale with similar behavior, is now documented as unsafe to imbue on an iostream or install as the global locale; the effect is undefined. All locales are now semi-transparent (translucent?), in that a locale which does not implement a facet delegates to the global locale. +------- BEGIN BOX 1 -------+ Effects TBS: +------- END BOX 1 -------+ 22.1.1.1 Type locale::category [lib.locale.category] typedef unsigned category; // as defined in <clocale>, e.g. LC_CTYPE 22.1.1.2 locale constructors [lib.locale.cons] locale(); locale(const locale& other); const locale& operator=(const locale& other) const; 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); 22.1.1.3 locale destructor [lib.locale.des] ~locale(); 22.1.1.4 locale::use [lib.locale.use] template <class Facet> const Facet& use() const; 22.1.1.5 locale::has [lib.locale.has] template <class Facet> bool has() const; 22.1.1.6 locale::name [lib.locale.name] const basic_string<char>& name() const; 22.1.1.7 locale::operator== [lib.locale.op==] bool operator==(const locale& other) const; 22.1.1.8 locale::operator!= [lib.locale.op!=] bool operator!=(const locale& other) const; 22.1.1.9 locale::isspace [lib.locale.isspace] template <class charT> bool isspace(charT c) const; 22.1.1.10 locale::isprint [lib.locale.isprint] template <class charT> bool isprint(charT c) const; 22.1.1.11 locale::iscntrl [lib.locale.iscntrl] template <class charT> bool iscntrl(charT c) const; 22.1.1.12 locale::isupper [lib.locale.isupper] template <class charT> bool isupper(charT c) const; 22.1.1.13 locale::islower [lib.locale.islower] template <class charT> bool islower(charT c) const; 22.1.1.14 locale::isalpha [lib.locale.isalpha] template <class charT> bool isalpha(charT c) const; 22.1.1.15 locale::isdigit [lib.locale.isdigit] template <class charT> bool isdigit(charT c) const; 22.1.1.16 locale::ispunct [lib.locale.ispunct] template <class charT> bool ispunct(charT c) const; 22.1.1.17 locale::isxdigit [lib.locale.isxdigit] template <class charT> bool isxdigit(charT c) const; 22.1.1.18 locale::isalnum [lib.locale.isalnum] template <class charT> bool isalnum(charT c) const; 22.1.1.19 locale::isgraph [lib.locale.isgraph] template <class charT> bool isgraph(charT c) const; 22.1.1.20 locale::toupper [lib.locale.toupper] template <class charT> charT toupper(charT c) const; 22.1.1.21 locale::tolower [lib.locale.tolower] template <class charT> charT tolower(charT c) const; 22.1.1.22 locale::operator() [lib.locale.op()] template <class charT> bool operator()(const basic_string<charT>& s1, const basic_string<charT>& s2) const; 22.1.1.23 locale::global [lib.locale.global] static locale global(const locale&); 22.1.1.24 locale::classic [lib.locale.classic] static const locale& classic(); 22.1.1.25 locale::transparent [lib.locale.transparent] static const locale transparent(); 22.1.1.26 operator<< [lib.locale.op<<] template <class charT> basic_ostream<charT>& operator<<(basic_ostream<charT>& s, const locale& l) 22.1.1.27 operator>> [lib.locale.op>>] template <class charT> basic_ostream<charT>& operator>>(basic_ostream<charT>& s, locale& l) 22.1.2 Locale classes [lib.locale.classes] 1 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.2.1 Class locale::facet [lib.locale.facet] // locale::facet -- base class for locale feature sets. // Any class deriving from facet must declare a *static* member: // static std::locale::id id; class locale::facet { facet(const facet&); // not defined void operator=(const facet&); // not defined void operator&() {} // not usable size_t refcount_; // MT environments must lock during add_ref() and rem_ref(). void add_ref() { if (this) ++refcount_; } void rem_ref() { if (this && refcount_-- == 0) delete this; } protected: facet(size_t refs = 0) : refcount_(refs-1) { } virtual ~facet() {} friend class locale; friend class imp; }; 22.1.2.2 Class locale::id [lib.locale.ctype.id] // class id: identification of a locale facet interface, // used as an index for lookup. class locale::id { void operator=(const id&); // not defined id(const id&); // not defined void operator&() {} // not usable mutable size_t id_; static size_t master_id_; // init'd to 0 by loader void init() // MT environments must lock during this function. { if (!id_) id_ = ++master_id_; } operator size_t() const { return id_; } public: id() {} // does *not* initialize member id_. friend class locale; }; 22.2 Standard locale facets [lib.std.facets] 22.2.1 The ctype facet [lib.facet.ctype] 22.2.1.1 Template class [lib.locale.ctype.base] locale::ctype_base struct locale::ctype_base : locale::facet { enum ctype { 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) }; protected: ctype_base(size_t refs = 0) : facet(refs) {} ~ctype_base() {} }; 22.2.1.2 Template class locale::ctype [lib.locale.ctype] template <class charT> class locale::ctype : public locale::facet { public: typedef charT char_type; protected: virtual bool do_is(ctype mask, charT c) const; virtual const charT* do_is( const charT* low, const charT* high, ctype* vec) const; virtual const char* do_scan_is( ctype mask, const charT* low, const charT* high) const; virtual const char* do_scan_not( ctype 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, charT c) const { return do_is(mask, c); } const charT* is(const charT* low, const charT* high, ctype* vec) const { return do_is(low, high, vec); } const charT* scan_is(ctype mask, const charT* low, const charT* high) const { return do_scan_is(mask, low, high); } const charT* scan_not(ctype mask, const charT* low, const charT* high) const { return do_scan_not(mask, low, high); } charT toupper(charT) const; { return do_toupper(c); } const charT* toupper(charT* low, const charT* high) const { return do_toupper(low, high); } charT tolower(charT c) const; { return do_tolower(c); } const charT* tolower(charT* low, const charT* high) const { return do_tolower(low, high); } charT widen(char c) const { return do_widen(c); } const char* widen(const char* lo, const char* hi, charT* to) const { return do_widen(lo, hi, to); } char narrow(charT c, char dfault) const { return do_narrow(c, dfault); } const charT* narrow(const charT* lo, const charT* char dfault, char* to) const { return do_narrow(lo, hi, dfault, to); } static locale::id id; ctype(size_t refs = 0) : locale::ctype_base(refs) {} protected: ~ctype() {} }; template <class charT> locale::id locale::ctype<charT>::id; 1 Class locale::ctype encapsulates the C library <cctype> features. The members of locale::ctype<charT> are much as in the previous proposal, with the addition of the scan_is() and scan_not() functions which find the first character in a buffer that does or does not satisfy a bit mask criterion. istream members are required to use locale::ctype<> for character classing. 2 A specialization locale::ctype<char> is provided, so that the member functions on type char may be implemented inline. Definitions of these functions have been provided for exposition. Only the char, and not the unsigned char and signed char forms, have been provided. The specialization is specified in the standard (and not left as an imple mentation detail) because it affects the derivation interface for locale::ctype<char>. 22.2.2 The ctype<char> facet [lib.facet.ctype.char] 22.2.2.1 Class ctype<char> [lib.locale.ctype.char] // a specialization, so that char operations may be inline. // (We must specify this in the standard because it affects the // derivation interface) class locale::ctype<char> : public locale::ctype_base { public: typedef char char_type; protected: const ctype* const table_; static const ctype classic_table_[UCHAR_MAX]; 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, char c) const { return table_[(unsigned char)c] & mask; } const char* is(const char* lo, const char* hi, ctype* vec) const { while (lo != hi) *vec++ = table_[(unsigned char)*lo++]; return lo; } const char* scan_is(ctype mask, const char* low, const char* high) const { while (low != high && !(table_[(unsigned char) *low++] & mask); return low; } const char* scan_not(ctype mask, const char* low, const char* high) const { while (low != high && (table_[(unsigned char)*low++] & mask); return low; } char toupper(char c) const; { return do_toupper(c); } const char* toupper(char* low, const char* high) const { return do_toupper(low, high); } char tolower(char c) const; { return do_tolower(c); } const char* tolower(char* low, const char* high) const { return do_tolower(low, high); } char widen(char c) const { return c; } const char* widen(const char* lo, const char* hi, char* to) const { memcpy(to, lo, hi-lo); return hi; } char narrow(char c, char /*dfault*/) const { return c; } const char* narrow(const char* lo, const char* hi, char /*dfault*/, char* to) const { memcpy(to, lo, hi-lo); return hi; } static locale::id id; ctype(const ctype* tab = 0, bool del = false, size_t refs = 0) : ctype_base(id, refs), table_(tab ? tab : classic_table_), delete_it_(tab ? del : false) {} protected: ~ctype() { if (delete_it) delete table_; } }; locale::id locale::ctype<char>::id; 22.2.2.2 Template class ctype_byname [lib.locale.ctype.byname] template <class charT> class locale::ctype_byname : public locale::ctype<charT> { // this class is specialized by vendors for char and wchar_t. protected: // ... declarations for all virtuals. public: ctype_byname(const char*, size_t refs = 0); protected: ~ctype_byname(); }; 22.2.2.3 Convenience interfaces [lib.locale.ctype.convenience] template <class charT> inline bool locale::isspace(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::SPACE, c); } template <class charT> inline bool locale::isprint(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::PRINT, c); } template <class charT> inline bool locale::iscntrl(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::CNTRL, c); } template <class charT> inline bool locale::isupper(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::UPPER, c); } template <class charT> inline bool locale::islower(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::LOWER, c); } template <class charT> inline bool locale::isalpha(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::ALPHA, c); } template <class charT> inline bool locale::isdigit(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::DIGIT, c); } template <class charT> inline bool locale::ispunct(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::PUNCT, c); } template <class charT> inline bool locale::isxdigit(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::XDIGIT, c); } template <class charT> inline bool locale::isalnum(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::ALNUM, c); } template <class charT> inline bool locale::isgraph(charT c) const { return use<locale::ctype<charT> >().is(locale::ctype<charT>::GRAPH, c); } template <class charT> inline charT locale::toupper(charT c) const { return use<locale::ctype<charT> >().toupper(c); } template <class charT> inline charT locale::tolower(charT c) const { return use<locale::ctype<charT> >().tolower(c); } 22.2.3 The numeric facet [lib.facet.numeric] 22.2.3.1 Template class num_get [lib.locale.num.get] template <class charT, class InputIterator = istreambuf_iterator<charT> > class locale::num_get : public locale::facet { public: typedef charT char_type; typedef InputIterator iter_type; typedef basic_ios<charT> ios; // members of locale::num_get take a locale argument because they // may need to refer to the locale's numpunct facet. 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; { return this->do_get(s, f, l, v); } iter_type get(iter_type s, ios& f, const locale&, long& v) const; { return this->do_get(s, f, l, v); } iter_type get(iter_type s, ios& f, const locale&, unsigned long& v) const; { return this->do_get(s, f, l, v); } // iter_type get(iter_type s, ios& f, const locale&, long long& v) const; // { return this->do_get(s, f, l, v); } iter_type get(iter_type s, ios& f, const locale&, double& v) const; { return this->do_get(s, f, l, v); } iter_type get(iter_type s, ios& f, const locale&, long double& v) const; { return this->do_get(s, f, l, v); } static locale::id id; num_get(size_t refs = 0) : locale::facet(refs) {} protected: ~num_get() {} }; template <class charT, class InputIterator = istreambuf_iterator<charT> > locale::id locale::num_get<charT, InputIterator>::id; 1 The classes locale::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 implementa tion refers to locale::numpunct features, which identify preferred numeric punctuation. Extractors and inserters for the standard iostreams are required to call locale::num_get and num_put member functions. The ios& argument is used both for format control and to report errors. 22.2.3.2 Template class num_put [lib.locale.num.put] template <class charT, class OutputIterator = ostreambuf_iterator<charT> > class locale::num_put : public locale::facet { typedef charT char_type; typedef OutputIterator iter_type; typedef basic_ios<charT> ios; // Members of locale::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. 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& l, bool v) const { return this->do_put(s, f, l, v); } iter_type put(iter_type s, ios& f, const locale& l, long v) const { return this->do_put(s, f, l, v); } iter_type put(iter_type s, ios& f, const locale& l, unsigned long v) const { return this->do_put(s, f, l, v); } // iter_type put(iter_type s, ios& f, const locale& l, long long v) const // { return this->do_put(s, f, l, v); } iter_type put(iter_type s, ios& f, const locale& l, double v) const { return this->do_put(s, f, l, v); } iter_type put(iter_type s, ios& f, const locale& l, long double v) const { return this->do_put(s, f, l, v); } static locale::id id; num_put(size_t refs = 0) : locale::facet(refs) {} protected: ~num_put() {} }; template <class charT, class OutputIterator = ostreambuf_iterator<charT> > locale::id locale::num_put<charT, OutputIterator>::id; 22.2.4 The numeric punctuation facet [lib.facet.numpunct] 22.2.4.1 Template class numpunct [lib.locale.numpunct] // locale::numpunct is used by locale::num_get and num_put facets. template <class charT> class locale::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) : locale::facet(refs) {} protected: ~numpunct() {} }; template <class charT> locale::id locale::numpunct<charT>::id; 1 numpunct<> specifies numeric punctuation. The base class provides classic "C" numeric formats, while the _byname version supports gen eral POSIX numeric formatting semantics. 22.2.4.2 Template class [lib.locale.numpunct.byname] numpunct_byname template <class charT> class locale::numpunct_byname : public locale::numpunct<charT> { // this class is specialized by vendors for char and wchar_t. protected: // ... declarations for all virtuals. public: numpunct_byname(const char*, size_t refs = 0); protected: ~numpunct_byname(); }; 22.2.5 The collation facet [lib.facet.collate] 22.2.5.1 Template class collate [lib.locale.collate] // locale.use<locale::collate>() is used for string comparisons. template <class charT> class locale::collate : public locale::facet { public: typedef charT char_type; typedef basic_string<charT> string; protected: virtual int do_collate(const char* low1, const char* high1, const char* low2, const char* high2);; virtual string do_transform(const char* low, const char* high); virtual long do_hash( const char* low, const char* high); public: int collate(const char* low1, const char* high1, const char* low2, const char* high2);; string transform(const char* low, const char* high); long hash(const char* low, const char* high); static locale::id id; collate(size_t refs = 0) : locale::facet(refs) {} protected: ~collate() {} }; template <class charT> locale::id locale::collate<charT>::id; 1 The class locale::collate<charT> provides features for use in the col lation of strings. A locale member function template, operator(), uses the collate facet to allow a locale to act directly as the predi cate argument for algorithms. The base class uses lexicographic ordering. 22.2.5.2 Template class [lib.locale.collate.byname] collate_byname template <class charT> class locale::collate_byname : public locale::collate<charT> { // this class is specialized by vendors for char and wchar_t. protected: // ... declarations for all virtuals. public: collate_byname(const char*); protected: ~collate_byname(); }; // this template function satisfies requirements for a // comparator predicate template argument: template <class charT> inline bool locale::operator()(const basic_string<charT>& s1, const basic_string<charT>& s2); { return use< collate<charT> >().collate(s1.begin(), s1.end(), s2.begin(), s2.end()) < 0; } 22.2.6 The codeset conversion facet [lib.facet.codecvt] 22.2.6.1 Template class codecvt [lib.locale.codecvt] template <class fromT, class toT, class stateT> class locale::codecvt : public locale::facet { // use two of these to convert both ways public: typedef fromT from_type; typedef toT to_type; typedef stateT state_type; enum result { ok = 0, partial, error } 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); public: result convert(stateT& state, const fromT* from, const fromT* from_end, const fromT*& from_next, toT* to, toT* to_limit, toT*& to_next); static locale::id id; codecvt(size_t refs = 0) : locale::facet(refs) {} protected: ~codecvt() {} }; template <class fromT, class toT, class stateT> locale::id locale::codecvt<fromT, toT, stateT>::id; 1 The class locale::codecvt<fromT, toT, stateT> is for use when convert ing 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" character 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.6.2 Template class [lib.locale.codecvt.byname] codecvt_byname template <class fromT, class toT, class stateT> class locale::codecvt_byname : public locale::codecvt<fromT, toT, stateT> { protected: // ... declarations for all virtuals. public: codecvt_byname(const char*, size_t refs = 0); protected: ~codecvt_byname(); }; 22.2.7 The date and time facet [lib.facet.date.time] 1 The classes locale::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.7.1 Template class time_get [lib.locale.time.get] template <class charT, class InputIterator = istreambuf_iterator<charT> > class locale::time_get : public locale::facet { public: typedef charT char_type; typedef InputIterator iter_type; typedef basic_ios<charT> ios; enum dateorder { NO_ORDER, DMY, MDY, YMD, YDM }; 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& l, tm* t) const { return do_get_time(s,f,l,t); } iter_type get_date(iter_type s, ios& f, const locale& l, tm* t) const { return do_get_date(s,f,l,t); } iter_type get_weekday(iter_type s, ios& f, const locale& l, tm* t) const { return do_get_weekday(s,f,l,t); } iter_type get_monthname(iter_type s, ios& f, const locale& l, tm* t) const { return do_get_monthname(s,f,l,t); } iter_type get_year(iter_type s, ios& f, const locale& l, tm* t) const { return do_get_year(s,f,l,t); } static locale::id id; time_get(size_t refs = 0) : locale::facet(refs) {} protected: ~time_get() {} }; template <class charT, class InputIterator = istreambuf_iterator<charT> > locale::id locale::time<charT, InputIterator>::id; 22.2.7.2 Template class [lib.locale.time.get.byname] time_get_byname template <class charT, class InputIterator = istreambuf_iterator<charT> > class locale::time_get_byname : public locale::time_get<charT, InputIterator> { protected: // ... declarations for all virtuals. public: time_get_byname(const char*, size_t refs = 0); protected: ~time_get_byname(); }; 22.2.7.3 Template class time_put [lib.locale.time.put] template <class charT, class OutputIterator = ostreambuf_iterator<charT> > class locale::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& l, struct tm const* t, char format, char modifier = ' ') const { return do_put(s,f,l,tmb,format,modifier); } static locale::id id; time_put(size_t refs = 0) : locale::facet(refs) {} protected: ~time_put() {} }; template <class charT, class OutputIterator = ostreambuf_iterator<charT> > locale::id locale::time_put<charT, OutputIterator>::id; 22.2.7.4 Template class [lib.locale.time.put.byname] time_put_byname template <class charT, class OutputIterator = ostreambuf_iterator<charT> > class locale::time_put_byname : public locale::time_put<charT, OutputIterator> { protected: // ... declarations for all virtuals. public: time_put_byname(const char*, size_t refs = 0); protected: ~time_put_byname(); }; 22.2.8 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 locale::moneypunct<> features if appropriate. locale::moneypunct<> provides basic format information for money pro cessing. The ios& argument is used for format control and to report errors. 22.2.8.1 Template class money_get [lib.locale.money.get] template <class charT, bool Intl = false, class InputIterator = istreambuf_iterator<charT> > class locale::money_get : public locale::facet { typedef charT char_type; const bool intl = Intl; 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& l, double& units) const { return do_get(s, f, l, units); } iter_type get(iter_type s, ios& f, const locale& l, string& digits) const { return do_get(s, f, l, digits); } static locale::id id; money_get(size_t refs = 0) : locale::facet(refs) {} protected: ~money_get() {} }; template <class charT, bool Intl = false, class InputIterator = istreambuf_iterator<charT> > locale::id locale::money_get<charT, Intl, InputIterator>::id; 22.2.8.2 Template class money_put [lib.locale.money.put] template <class charT, bool Intl = false, class OutputIterator = ostreambuf_iterator<charT> > class locale::money_put : public locale::facet { public: typedef charT char_type; const bool intl = Intl; 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& l, double units) const { return do_put(s, f, l, units); } iter_type put(iter_type s, ios& f, const locale& l, const string& dgts) const { return do_put(s, f, l, dgts); } static locale::id id; money_put(size_t refs = 0) : locale::facet(refs) {} protected: ~money_put() {} }; template <class charT, bool Intl = false, class OutputIterator = ostreambuf_iterator<charT> > locale::id locale::money_put<charT, Intl, OutputIterator>::id; 22.2.9 The money punctuation facet [lib.facet.moneypunct] 22.2.9.1 Template class moneypunct [lib.locale.moneypunct] template <class charT, bool International = false> class locale::moneypunct : public locale::facet { public: typedef charT char_type; const bool intl = International; typedef basic_string<charT> string; enum part { SYMBOL='$', SIGN='-', SPACE=' ', VALUE='v', NONE=' ' }; struct pattern { char field[4]; }; 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_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 format() const { return do_format(); } static locale::id id; moneypunct(size_t refs = 0) : locale::facet(refs) {} protected: ~moneypunct() {} }; template <class charT, bool Intl = false> locale::id locale::moneypunct<charT, Intl>::id; 1 This provides money punctuation, similar to numpunct above. 22.2.9.2 Template class [lib.locale.moneypunct.byname] moneypunct_byname template <class charT, bool Intl = false> class locale::moneypunct_byname : public locale::moneypunct<charT, Intl> { protected: // ... declarations for all virtuals. public: moneypunct_byname(const char*, size_t refs = 0); protected: ~moneypunct_byname(); }; 22.2.10 The message retrieval facet [lib.facet.messages] 1 Class locale::msg<charT> implements POSIX message retrieval. It should be flexible enough to retrieve messages from X, MS Windows, or Macintosh resource files as well. 22.2.10.1 Template class msg [lib.locale.msg] template <class charT> class locale::msg { 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& default) 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& default) const { return do_get(c, set, msgid, default); } void close(catalog c) const { do_close(c); } static locale::id id; msg(size_t refs = 0) : locale::facet(refs) {} protected: ~msg() {} }; template <class charT> locale::id locale::msg<charT>::id; 22.2.10.2 Template class msg_byname [lib.locale.msg.byname] template <class charT> class locale::msg_byname : public locale::msg<charT> { protected: // ... declarations for all virtuals. public: msg_byname(const char*, size_t refs = 0); protected: ~msg_byname(); }; 22.2.11 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 Here is an 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<locale::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 locale::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 locale::numpunct<charT> facet interface: // my_bool.C #include <iostream> #include <locale> #include <string> namespace My { using namespace std; typedef locale::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 Headers: --<clocale> 2 Table 2: Table 2--Header <clocale> synopsis +------------------------------------------------+ | Type Name(s) | +------------------------------------------------+ |Macros: | | LC_MONETARY LC_NUMERIC LC_TIME | +------------------------------------------------+ |Struct: lconv | +------------------------------------------------+ |Functions: localeconv setlocale | +------------------------------------------------+ SEE ALSO: ISO C subclause 7.10.4.