Шаг 534.
Библиотека STL.
Интернационализация. Строение объекта локального контекста

    На этом шаге мы рассмотрим строение и использование объекта локального контекста.

    Локальный контекст C++ представляет собой неизменяемый контейнер для фацетов. Класс locale определяется в заголовочном файле <locale> следующим образом:

namespace std {
    class locale {
    public:
      // Глобальные объекты локальных контекстов
      static const locale& classic(); // Классический локальный контекст C
      static       locale  global(const locale&);  // Глобальное назначение
                                                   // локального контекста
      // Внутренние типы и значения
      class facet;
      class id;
      typedef int category;
      static const category none, numeric, time, monetary,
                            ctype, collate, messages, all;

      // Конструкторы
      locale() throw();
      explicit locale (const char* name);

      // Создание локального контекста на базе существующих контекстов
      locale (const locale& loc) throw();
      locale (const locale& loc, const char* name, category);
      template <class Facet>
        locate (const locale& loc, Facet* fp);
      locale (const locale& loc, const locale& loc2, category);

      // Оператор присваивания
      const locale& operator= (const locale& loc) throw();
      template <class Facet>
        locale combine (const locale& loc);

      // Деструктор
      ~locale() throw();

      // Имя (если есть)
      basic_string<char> name() const;

      // Сравнения
      bool operator== (const locale& loc) const;
      bool operator!= (const locale& loc) const;

      // Сортировка строк
      template <class charT, class Traits, class Allocator>
        bool operator() (
          const basic_string<charT,Traits,Allocator>& s1,
          const basic_string<charT,Traits,Allocator>& s2) const;
    };

    // Работа с фацетами
    template <class Facet>
      const Facet& use_facet (const locale&);
    template <class Facet>
      bool has_facet (const locale&) throw();
}

    У локальных контекстов есть одна специфическая особенность - механизм обращения к объектам фацетов, хранящимся в контейнере. Обращение к фацету локального контекста производится по типу этого фацета, который интерпретируется как индекс. Поскольку фацеты обладают разными интерфейсами и предназначаются для разных целей, желательно, чтобы функции доступа к локальным контекстам возвращали тип, соответствующий индексу; именно это и происходит при "индексировании" по типу фацета. Другое достоинство этого механизма состоит в том, что интерфейс безопасен по отношению к типам.

    Объекты локальных контекстов неизменны. Это означает, что фацеты, хранящиеся в локальных контекстах, невозможно модифицировать (кроме присваивания локальных контекстов). Модификации локальных контекстов создаются посредством объединения существующих контекстов и фацетов с формированием нового контекста. В таблице 1 перечислены конструкторы локальных контекстов.

Таблица 1. Конструкторы локальных контекстов
Выражение Описание
locale() Создает копию текущего локального контекста, назначенного глобально
locale(name) Создает объект локального контекста для заданного имени
locale(loc) Создает копию локального контекста lос
locale(loc1, loc2, cat) Создает копию локального контекста loc1, в которой все фацеты из категории cat заменяются фацетами локального контекста loc2
locale(loc, name, cat) Эквивалент locale(loc, locale(name), cat)
locale(loc,fp) Создает копию локального контекста lос и устанавливает фацет, на который ссылается указатель fp
loc1 = loc2 Присваивает локальный контекст lос2 объекту loc1
loc1.template combine<F>(loc2) Создает копию локального контекста loc1, в которой фацет типа F берется из lос2

    Почти все конструкторы создают копию другого объекта локального контекста. Простое копирование объекта считается относительно дешевой операцией. Фактически оно сводится к заданию указателя и увеличению счетчика ссылок. Создание модифицированного локального контекста обходится дороже, поскольку при этом приходится изменять счетчики ссылок для всех фацетов, хранящихся в локальном контексте. Хотя стандарт не дает гарантий относительно эффективности этой операции, весьма вероятно, что во всех реализациях копирование локальных контекстов будет производиться достаточно эффективно.

    Два конструктора из таблицы 1 получают имена локальных контекстов. Передаваемые имена не стандартизированы (кроме имени С). Однако стандарт требует, чтобы в документации, прилагаемой к стандартной библиотеке C++, были перечислены допустимые имена. Предполагается, что большинство реализаций поддерживает имена, представленные на 530 шаге.

    Функцию combine() стоит пояснить подробнее, поскольку в ней используется возможность, относительно недавно реализованная в компиляторах. Она представляет собой шаблонную функцию с явно заданным аргументом. Это означает, что тип аргумента шаблона не определяется по значению аргумента, поскольку такого значения попросту нет. Вместо этого аргумент шаблона (в данном случае - тип F) задается явно.

    В двух функциях для обращения к фацетам объекта локального контекста используется одинаковая методика (таблица 2). Однако эти две функции являются глобальными шаблонными функциями, поэтому уродливый синтаксис с ключевым словом template становится излишним.

Таблица 2. Работа с фацетами
Выражение Описание
has_facet<F>(loc) Возвращает true, если локальный контекст lос содержит фацет типа F
use_facet<F>(loc) Возвращает ссылку на фацет типа F, хранящийся в локальном контексте lос

    Функция use_facet() возвращает ссылку на фацет. Тип ссылки соответствует типу, переданному явно в аргументе шаблона. Если локальный контекст, переданный в аргументе, не содержит соответствующего фацета, функция генерирует исключение bad_cast. Чтобы узнать, присутствует ли в заданном локальном контексте некоторый фацет, воспользуйтесь функцией has_facet().

    Остальные операции локальных контекстов перечислены в таблице 3. Имя локального контекста поддерживается в том случае, если контекст был сконструирован по заданному имени или одному (или нескольким) именованным локальным контекстам. Однако и в этом случае стандарт не дает гарантий относительно построения имени, полученного при объединении двух локальных контекстов. Два локальных контекста считаются идентичными, если один из них является копией другого или если оба локальных контекста имеют одинаковые имена. Было бы естественно считать, что два объекта идентичны, если один из них является копией другого. Но что делать с именами? Предполагается, что имя локального контекста отражает имена, используемые для конструирования именованных фацетов. Например, имя локального контекста может быть сконструировано объединением имен фацетов в определенном порядке, разделенных заданными символами. Вероятно, такая схема позволит определить идентичность двух объектов локального контекста, если они были сконструированы посредством объединения одних и тех же именованных фацетов. Иначе говоря, стандарт требует, чтобы два локальных контекста, содержащих одинаковые именованные фацеты, считались идентичными.

Таблица 3. Операции с локальными контекстами
Выражение Описание
loc.name() Возвращает имя локального контекста loc в виде string
loc1 == lос2 Возвращает true, если локальные контексты loc1 и lос2 идентичны
loc1 != lос2 Возвращает true, если локальные контексты loc1 и lос2 не идентичны
loc(str1,str2) Возвращает логический признак сравнения строк str1 и str2 в порядковом отношении (то есть проверяет, что str1 меньше str2)
locale::classic() Возвращает locale("C")
locale::global(loc) Назначает локальный контекст loc как глобальный и возвращает предыдущий глобально назначенный локальный контекст

    Оператор () позволяет использовать объект локального контекста для сравнения строк. При этом строки, переданные в аргументах, сравниваются в порядковом отношении, и задействуется фацет collate. Иначе говоря, фацет collate проверяет, будет ли одна строка меньше другой по критериям объекта локального контекста. Такое поведение типично для объектов функций STL, поэтому объект локального контекста может использоваться в качестве критерия сортировки для алгоритмов STL, работающих со строками. Например, сортировка вектора по правилам немецкого локального контекста выполняется следующим образом:

std::vector<std::string> v;
.   .   .   .   .
// Сортировка строк в немецком локальном контексте 
std::sort (v.begin(), v.end(),  //Интервал
              locale("de_DE"));   // Критерий сортировки

    На следующем шаге мы рассмотрим строение фацетов.




Предыдущий шаг Содержание Следующий шаг