Saturday, January 11, 2025

locale class

Overview
In C++, a locales are represented by a locale object, which  is a collection of indexed facets. It also contains a basic_regex object.

Details
The locale class defines following.

category
This a typedef for int. It assigns bitmask values for different facets. Note that locale class members use this numbers not the lcids.
NameFacets
const category noneZero value indicating no facet category
const category collatecollate facet type can be used for collate comparison of strings
const category ctype 
  1. ctype facet type encapsulates character classification features.
  2. codecvt facet type encapsulates conversion of character strings, including wide and multibyte, from one encoding to another.
const category monetary
  1. moneypunct facet encapsulates monetary value format preferences. 
  2. money_get facet encapsulates monetary parsing rules.
  3. money_put facet encapsulates monetary formatting rules.
const category numeric
  1. numpunct  facet encapsulates number formatting rules.
  2. num_get facet encapsulates number parsing rules.
  3. num_put facet encapsulates number formatting rules.
const category time
  1. time_get facet encapsulates Date and Time parsing rules.
  2. time_put facet encapsulates Date and Time formatting  rules.
const category messagesmessages
System responses
const category allAll the categories. i.e., collate | ctype | monetary | numeric | time | messages. This means all the facets.

class ID
This is a helper class that defines an unique id for facets. It's defined as below.
class locale::id 
{
public:
  id();
  void operator= (const id&) = delete;
  id (const id&) = delete;
}
This class provides implementation-specific identification of a locale facet. Each facet has a public static member named id of type locale::id and each locale object maintains a list of facets it implements, indexed by their ids.

Facets with the same id belong to the same facet category and replace each other when added to a locale object.

class facet
A facet is a class describing a locale feature set associated to a specific cultural aspect. This is a base class for all facets. It provides a common base class so that locales could store pointers to the facets they implement in a single indexed container, and it abstracts support for facet reference counting.

Whenever a facet is added to a locale, the locale increments the reference count in the facet. Whenever a locale is destructed or modified, it decrements the reference count in each facet it no longer implements. Whenever a facet's reference count becomes zero, the locale deletes the facet.

This base class basically implements a protected constructor that takes one parameter. This parameter, refs, shall be 0 (zero) if the facet has to be automatically destroyed when the last locale object containing that facet is destroyed, and 1 (one) if it does not have to.

Derived classes defining specific facets shall also have a constructor taking a refs parameter, which is passed to their base class.

class locale::facet 
{
protected:
  explicit facet (size_t refs = 0);
  virtual ~facet();
  facet (const facet&) = delete;
  void operator= (const facet&) = delete;
}}

Note that unlike in C, multiple instances of locale objects can coexist. The following diagram shows the relation.

Constructors
NameDescription
locale()Default constructor. Constructs a copy of the global C++ locale, which is the locale most recently used as the argument to locale::global or a copy of locale::classic() if no call to locale::global has been made.

Example
    locale l;
    //prints:C
    cout << l.name();
locale 
(const locale& x)
Copy constructor.
locale
(const char* std_name)
Constructs a copy of the system locale with specified std_name (such as "C", "en_US.UTF-8", or "en-US"), if such locale is supported by the operating system. The locale constructed in this manner has a name.

Example
locale l("en_US.UTF-8");
//prints:en_US.UTF-8
cout << l.name();
locale
(const string& std_name)
Same as locale(std_name.c_str())
locale
(const locale& x, 
const char* std_name, category cats)
Constructs a copy of x except for all the facets identified by the cats argument, which are copied from the system locale identified by its std_name. The locale constructed in this manner has a name if and only if other has a name.

Example
locale l(locale("en_US.UTF-8"),"de_DE.UTF-8",locale::monetary);
cout.imbue(l);
//prints:12,34 €
cout  << showbase << put_money(1234);
locale
(const  locale& x, 
const string& std_name, category cats)
 Equivalent to locale(x, std_name.c_str(), cats).
locale
(const locale& x, const locale& y, 
category cats)
Constructs a copy of except for all the facets identified by the cats argument, which are copied from y.
locale
(const locale& x, Facet* f)
Constructs a copy of x except for the facet of type Facet (typically deduced from the type of the argument) which is installed from f. If f is a null pointer, the constructed locale is a full copy of other. 

Example
struct custom_tf : numpunct<char>
{
    string do_truename()  const { return "nija"; }
    string do_falsename() const { return "sullu"; }
};

locale l(locale(),new custom_tf);
cout.imbue(l);
cout << boolalpha;
//prints nija 
cout << true  << endl; 
//prints sullu
cout << false << endl; 

Methods
NameDescription
template <class Facet>
locale combine 
(const locale& x)
Constructs a locale object which is a copy of *this except for the facet of type Facet, which is copied from x.
Returns the new, nameless, locale.

Example
    const double number = 1000.25;
    //prints:"C" locale: 1000.25
    cout << quoted("C") << " locale: " << number << endl;
    locale loc = locale()
        .combine<numpunct<char>>(locale("en_US.UTF8"));
    cout.imbue(loc);
    //prints:"C" locale with en_US numpunct: 1,000.25
    cout << quoted("C") << " locale with en_US numpunct: " << number << endl;
string name() 
Returns the name of the locale, which is the name by which it is known to the operating system, such as "POSIX" or "en_US.UTF8" or "English_United States.1252". 
If the locale is not a copy of a system-supplied locale, the string "*" is returned.
The name of the locale or "*" if unnamed.

Example
    locale loc(locale(), new ctype<char>);
    /*prints
    The default locale is C
    The user's locale is en_US.UTF-8
    A nameless locale is *
    */
    cout << "The default locale is " << locale().name() << endl
              << "The user's locale is " << locale("").name() << endl
              << "A nameless locale is " << loc.name() << endl;

bool operator==
 (const locale& x)
Tests two locales for equality and returns true if succeeds. Named locales are considered equal if their names are equal. Unnamed locales are considered equal if they are copies of each other.

Example
//b:true
bool b{(cout.getloc() == locale("C"))};
bool operator()
(const string& s, const string& s2)
Compares two string arguments s and s2 according to the lexicographic comparison rules defined by this locale's collate facet. This operator allows any locale object that has a collate facet to be used as a binary predicate in the standard algorithms (such as sort) and ordered containers (such as set).
Return true if s is lexicographically less than s2, false otherwise.

Example
    vector<wstring> v{L"år",L"ängel"};
    //v:ängel,år 
    sort(v.begin(), v.end());
    
    //v:år,ängel 
    sort(v.begin(), v.end(), locale("sv_SE.UTF-8"));
const locale& classic()
This is a static function.
Obtains a reference to the C++ locale that implements the classic "C" locale semantics. This locale, unlike the global locale, cannot be altered.
Returns a reference to the "C" locale.

locale global
(const locale& loc)
This is a static function.
Replaces the global C++ locale with loc, which means all future calls to the std::locale default constructor will now return a copy of loc. If loc has a name, also replaces the C locale as if by setlocale(LC_ALL, loc.name().c_str());. This function is the only way to modify the global C++ locale, which is otherwise equivalent to std::locale::classic() at program startup.
The previous value of the global C++ locale.

Example
    // the "C" locale
    locale foo;
    //prints:C
    cout << foo.name() << endl;
    
    locale::global(locale(""));
    locale bar;
    //prints:en_US.UTF-8
    cout << bar.name() << endl;

IO Stream classes and locale
IO Stream classes contains an instance of locale object which is used to during formatted I/O operations. A specific locale object can be set using imbue() method defined in IO Stream classes.
In the examples below, streams cincout and cerr are assigned different locales.
//sets classic C locale
cin.imbue(locale::classic());

//sets global locale
cout.imbue(locale());

//sets a specific locale
cerr.imbue(locale("en_US.ISO8859-1"));

//to print unicode letters in filestream in windows
ofstream ofs("output.txt");
ofs.imbue(locale(locale("kn_IN"), new codecvt_utf8<wchar_t>()));
This is depicted in this  example 2.

Helper functions
NameDescription
template< class Facet >
bool has_facet
(const locale& loc)
Checks if the locale loc implements the facet Facet.
Returns true if the facet Facet was installed in the locale loc, false otherwise.

Example
locale l;
//b:true
bool b = has_facet<ctype<char>>(l);
//b:false
b = has_facet<ctype<char16_t>>(l);
template< class Facet >
const Facet& use_facet
(const locale& loc)
Obtains a reference to a facet implemented by loc.
Returns a reference to the facet. The reference returned by this function is valid as long as any locale object refers to that facet.

Example
    /*prints
    Your currency string is USD 
    Your currency string is EUR 
    Your currency string is GBP
   */
    for (const char* name: {"en_US.UTF-8", "de_DE.UTF-8", "en_GB.UTF-8"})
        cout << "Your currency string is "
                  << use_facet<moneypunct<char, true>>(locale{name}).
                     curr_symbol() << endl;

Facets
As discussed earlier, a locale is a collection of facets. A  facet defines a specific aspect of regional setting. 

The facet objects in a locale can be accessed only by calling use_facet() as below. 
std::use_facet<std::numpunct<char>>(loc)

Every facet is derived from std::locale::facet or its derivative and has the following rough structure.
class facet_name:locale::facet
{
public:
	XXX function();
	YYY function2();
	static locale::id id;
protected:
	virtual XXX do_function();
	virtual YYY do_function2();
};

Each facet has a public static member named id of type locale::id uniquely identifying its category.
The public methods provides user interface to external clients. These internally call the virtual protected methods. 
It's possible to override the default behavior of an existing facet and even add a new facet to a locale

No comments:

Post a Comment