На этом шаге мы приведем требования и рекомендации по созданию собственных фацетов.
Возможности локального контекста определяются содержащимися в нем фацетами. Все локальные контексты заведомо содержат минимальный набор
стандартных фацетов. В описаниях отдельных фацетов, приведенных далее, указано, какие специализации гарантированно присутствуют в контексте.
Помимо перечисленных реализация стандартной библиотеки C++ может включить в локальный контекст дополнительные фацеты. Важно
понимать, что пользователь также может добавить собственные фацеты или установить их вместо стандартных фацетов.
На 533 шаге рассматривается процедура установки фацета в локальном контексте. Например, класс germanBoolNames
был объявлен производным от класса numpunct_byname<char> одного из стандартных фацетов и установлен в локальном контексте при
помощи конструктора, в аргументах которого передаются локальный контекст и фацет. Но что нужно для того, чтобы создать собственный фацет?
В качестве фацета может использоваться любой класс F, удовлетворяющий двум требованиям.
- Класс F является открытым производным от класса locale::facet. Базовый класс в основном определяет механизмы подсчета
ссылок, используемые во внутренней работе объектов локального контекста. Кроме того, он объявляет закрытыми копирующий конструктор и
оператор присваивания, что предотвращает копирование или присваивание фацетов. - Класс F содержит открытую статическую переменную id типа locale::id. Эта переменная используется для поиска
фацета в объекте контекста по его типу. Применение типа в качестве индекса прежде всего направлено на обеспечение типовой безопасности интерфейса.
Во внутреннем представлении для работы с фацетами используется обычный контейнер с целочисленными индексами.
Стандартные фацеты соответствуют не только этим требованиям, но и некоторым специальным рекомендациям - не обязательным, но весьма полезным.
- Все функции класса объявляются константными. Это полезно, поскольку функция use_facet() возвращает ссылку на константный фацет.
Функции, не объявленные константными, вызываться не могут. - Все открытые функции объявляются невиртуальными и передают запросы защищенным виртуальным функциям. Имя защищенной функции совпадает
с именем открытой функции, с добавлением префикса do_. Например, функция numpunct::truename() вызывает функцию
numpunct::do_truename(). Подобная схема выбора имен помогает избежать замещения функций при переопределении только одной из
нескольких виртуальных функций с одинаковыми именами. Например, класс num_put содержит несколько функций с именем put.
Кроме того, программист базового класса может включить в невиртуальные функции дополнительный код, который будет выполняться даже в случае
переопределения виртуальных функций.
Следующее описание стандартных фацетов относится только к открытым функциям. Чтобы изменить фацет, всегда приходится переопределять соответствующие
защищенные функции. Определение функций с таким же интерфейсом, как у открытых функций фацета, всего лишь перегрузит их, поскольку эти
функции не являются виртуальными.
Для большинства стандартных фацетов определяется версия с суффиксом _byname. Она является производной от стандартного фацета и
создает специализацию для соответствующего имени локального контекста. Так, класс numpunct_ byname создает фацет numpunct для
локального контекста с заданным именем. Например, команда создания немецкого фацета numpunct может выглядеть так:
std::numpunct_byname("de_DE")
Классы _byname создаются в процессе внутренней работы конструкторов локального контекста, получающих имя в виде аргумента. Для
каждого стандартного фацета, поддерживающего имя, конструирование экземпляра этого фацета производится соответствующим классом _byname.
На следующем шаге мы рассмотрим числовое форматирование.