______________________________________________________________________
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.