Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 219
Текст из файла (страница 219)
1022 Приложение (). Локализация го!ау'(сопл! !оса!еь ту 1оса1е) ( слог с = иве ~все!<питрипс!<слег» (ту 1оса1е) .Иес1та! рот!(); Уиспольэуеи (г стандартный фасет (г ... 31'(Ьав уасег<Епсгур!> (ту упса!в) ) ,(ге ту (оса1е есть фосет Епоурэ? ( сопл! Епсгур!ь у = иэе уасе!<Епсгур!> (ту 1оса1е); сопл! Сгур!о с =/.де! <тур!о (); У...
) ~У ... Обратите внимание на то, что изе уасе! возврашает ссылку на константный фасет, так что мы не можем присвоить этот возврат неконстантным переменным. Это разумно, поскольку фасеты полагаются неизменяемыми и содержащими лишь константные методы. Если мы попытаемся вызвать иве уасе!<Х> (1ос), а 1ос не содержит фасет Х, то изе ~псе! сгенерирует исключение Ьаэ( саэт (514.!О). Так как гарантируется, что стандартные фасеты доступны во всех контекстах локализации (5Е).4), то в этом случае нет необходимости обращаться к Ьаз 1асег. Для стандартных фасетов изе уасег никогда не сгенерирует исключение Ьаэ( саэт. Как могут быть реализованы изе уасег и Ьаз уасеГ1 Вспомним, что 1оса1е можно рассматривать как тир<И,уасег*> (5Р.2). Отталкиваясь от полученного в параметре шаблона расе! типа фасета, реализации иве уасе! или Ьаз )асе! могут обратиться к сисе!:: Ы и использовать его для поиска соответствующего фасета.
Упрошенные реализации Ьазуасе! и изе уасе! могут выглядеть следующим образом: д'псевдореализацит пусть (оса(е содержит тар<Щасе(ь> названный!все! тар <етр!а!в<с!аэв Расе!> Ьоо) Ьав 1асе! (сопл! !оса)еь !ос) гйгое () ( сопт !оса!в:: 1асе!* 1'= 1ос.уасе! тар (Гасе!:: Ы] ) ге(игп !'? ггие: га!веэ ) гетр!а!е<с!азэ Расе!> сопи Гасе!ь иэе !асе! (сопл! !оса)еь 1ос) ( сонм!оса!в::~все!*1 = 1ос.(асе! тор[расе!::ы); э! (1) гесагп в!вас сил!<сонм Расе!в > ( "'1) ! гйгон Ьад сов!(); ) Взглянув по-другому на механизм уасег::Ы, можно реализовать некую форму полиморфизма на этапе компиляции. Очень близкий к изе 1асе! результат можно получить применением операции ((упапйс сазп Однако специализированный шаблон изе уасе! может быть реализован гораздо эффективнее общего механизма на базе операции Нуиат1с савв На самом деле Ы идентифицирует скорее интерфейс и поведение, нежели класс.
То есть если интерфейсы двух классов фасетов в точности совпадают при одинако- Р.З. Фасеты 1023 вой семантике (по отношению к контексту локализации), они должны идентифицироваться одним и тем же 1»!. Например, со1!аге<сйаг> и сойаге Ьуиате<сЬаг> для !оса!е взаимозаменяемы, и потому оба идентифицируются при помоши одного и того же сойаге<сЬаг>:: И 513.4.1).
Если мы определяем фасет с новым интерфейсом — например Еисгург в функции 3() — мы должны определить и соответствуюший Ы для его идентификации (см. 5Р.3.2 и 93.4.1). (л.3.2. Простой пользовательский фасет Стандартная библиотека предоставляет стандартные фасеты, учитывающие наиболее важные аспекты национальных особенностей, такие как наборы символов и ввод/вывод чисел. Чтобы познакомиться с механизмом фасетов вне нх связи с широко применяемыми типами, влекущими за собой всякие сложности, а также вне забот о высокой эффективности, которые их сопровождают, рассмотрим фасет для тривиального пользовательского типа: епи»и Зеазоп (зрг(пО, зиттег,уаП, и 1игег) ! Это простейший пользовательский тип, который я вообще могу себе представить.
Показанный ниже стиль ввода/вывода может использоваться (с минимальными изменениями) для большинства простых пользовательских типов: с(азз Беазоп ш: риЫЫ Ь»сне::Завез ( риЫ»с: Яеазоп ю(тг1= О): 1оса1е::)асег(1) ( ) -Зеазоп Ы () ( ) 1) обеспечивает возможность уничтожения объектов Беозоп !о ЯР.3) Ыииа1 соим зйзпяь и» зй (Яеазоп х) сопл! = О! )) строковое представление для х ар!осе 5еазоп соггсзроп»(!пя го з т к: г)ггиа1 Ьоо1)гот зй (сопл! згг!пдв з, Яеазопа х) соил! = О! майе!оса(е»»ЫТА У объект идентификации фасето ЯР.2, ЗР.3, ЗР.3.
1) )» )оса!в:: 1Й Яеазоп и:: Ы! )) определяем идентифицирующий объект Для простоты данный фасет ограничивается представлениями, использующими лишь сйаг. Класс Яеазоп ю обеспечивает общий абстрактный интерфейс ко всем фасетам иерархии наследования. Чтобы определить вывод объектов типа Яеазоп для конкретного контекста локализации, мы наследуем класс от зеазои го, определяя при этом надлежащим образом функции го згг Н и угоиз згг() . Вывести Яеазои просто. Если у потока имеется фасет Яеазоп го, то мы можем использовать его для преобразования времени года' в строку. В противном случае мы можем вывести целое значение: озггеать орегазог«(озггеата з, Яеазоп х) ( сопя!!оса(еь 1ос = з.дег)ос () ! Развлекаем з(геат з !оса!е (32!.
7!) Время года по-англнйскн — зеазоп. — Прии, ред. Приложение (). Локализация 1024 (!(Ьаз !асе«Яеазои !о> (1ос) ) ге<ига з « изе /асе«Яеазоп ю> (!ос) .<о з<г(х) ге<игп я «<п< (х) < ) Обратите внимание, что данная операция «реализована посредством вызова этой же операции, но для других типов. Таким образом, мы извлекаем пользу из простоты вызова операций «по сравнению с прямым доступом к буферам потока оя<геаи<, из учета этими операциями контекста локализации и из реализованной ими обработки ошибок.
Стандартные фасеты напрямую обращаются к буферам потоков (5<л.4.2.2, 9Э.4.2.3) ради максимальной эффективности и гибкости, но для многих простых пользовательских типов нет никакой необходимости опускаться на уровень абстракции я<геаи<ЬиЯ Как обычно, ввод немного сложнее вывода: Ьиеата орега<ог» (<з<геатя з, Яеазопь х) ( сопя<<оса!ей !ос = з.ее<!ос() ) (Г(Ьаз ~асе<<Яеазои ю> (<ос) ) ( сопз< Яеазоп юа !'= изе /асе«Яеазои !о> (<ос); з<г<пд Ьи1 < <) (! (з»Ьи!'яя Г./гот юг(Ьи(,х) ) ) з.зе<юа<е(1оз Ьазе::)аИЬ!<) < ге<ига з; У извлекаем я<геотз <оса<е Д2!.7.!) /У читаем алфавитное представление // читаем числовое представление ии 1< з»« х = Яеазои (<) ге<ига з< ) !п< та!п () ( Хеаяои х< /У Используем лакал-цию ио умолчанию !нет фосета Беазоп <о) — ввод/вывод целых: ст » х< сои< «х « си<И< !оса1е !ос(!оса1е(), ив<я 1/Б зев<оп <о) ) сои<.
ииЬие (<ос) ) 7/ используем локализацию с фасетом яеаяоп !о <<и. ЬиЬие (<ос) < // используем локализацию с фасетом 5еаяоп (о с!и» х< сои< «х «еи<И< Обработка ошибок проста и следует стилю обработки ошибок для встроенных типов. То есть если вводимая строка не соответствует стилю Яеазои в рамках текущего контекста локализации, поток устанавливается в состояние ГаИ. Если допускаются исключения, то следует обрабатывать исключения <оз Ьазе::~аИиге ($21.3.6).
Вот тривиальная тестовая программа: 1025 [) 3. Фасеты Для входа зиттег эта программа отреагирует следующим выводом: зиттег Для достижения этого результата мы должны определить ЮЯ зеаюп ю с целью задания строкового представления времен года и замещения функций интерфейса ВЬиоп яо, которые преобразуют строковые представления в перечисления и обратно: е!азз 118 зеазоп !о: риЬ11е Беазоп 1о ( з!анс сопт ззг!пВ зеазопз [ ] 1 риЫ(е: сопя! зяг(пяз !о ззг(Зеазоп) соптг Ьоо1)гот з(г(сопя! з!г!пяз, Беазопя) сопя!! 11 обратите внимание: отсутствует (18 яеозоп !охЫ еопт з!г!пя (13 зеаюп ш:: яеазопз [ ] = ( "зрг(пВ", "зиттег", "!а11", "п1п!ег" ); сопя! ззг(пяя 115 зеаюп ш::го згг($еазоп х) еопз! ( о(х<зрг1пВ ] ( пш!ег<х) ( зт!1с сопя! з!гшя т = "по — зиеЬ-яеаюп" 1 геаип т; ) ге!игп зеаюпз [х]; ) Ьоо! 118 зеазоп 1о::ггот тг(солт згг!пяя з, Яеазопа х) еопт ( сопя! з!г!п8* Ьея = язеазопз (зрг1пя]; сопя! зп[пя* епй = ьзеазопз [пшзег] е1; еопм я!г!пя* р = !)пВ(Ьея, епд,з) 1 ~УВ381, 8185 2 и (р==епй) ге!ига)а!ее! х = Юеазоп (р-Ьея) 1 ге!игп ягиег Заметьте, что поскольку УЯ зеазоп ю является просто реализацией интерфейса Яеазоп !о, я не определял!д для ЮЯ зеаюп !о.
Вообще, если мы хотим использовать 0Я зеазоп 1о в качестве Яеазоп ш, мы не можем задавать для 113 зеазоп 1о его собственный Ы. Операции класса !оса!е, например Ьаз уасег ЯР.З.!), полагаются на то, что фасеты, реализующие одну и ту же концепцию, идентифицируются одним и тем же и! 60.3). Единственным вопросом в данной реализации остается вопрос, что делать, когда для вывода предоставляется некорректный Яеазоп? Случаи появления некор- 1026 Приложение ().
Локализация ректных значений для простых пользовательских типов не столь уж необычны, так что стоит заранее принять во внимание подобную ситуацию. Я мог бы сгенерировать исключение. Но когда имеешь дело с простым выводом, предназначенным для человеческих глаз, полезно подготовить специальное визуальное представление для некорректных значений. Обратите внимание, что при вводе стратегия обработки ошибок передана операции «, в то время как при выводе эта стратегия оставляется функции фасета го згг() . Это было сделано с целью проиллюстрировать возможные варианты проектирования. В настоящих, промышленных проектах функции фасета либо реализуют обработку ошибок как ввода, так и вывода, либо перепоручают все это операциям» и «.
Данный проект для оеаюл ю полагается на то, что производные классы предоставляют специфичные для локализации строки. В альтернативном дизайне эеаюп !о сам мог' бы извлекать строки из соответствующего хранилища (см. 5П.4.7). Создание класса оеаюл ю, которому строки времен года передаются в качестве аргументов конструктора, оставляется в качестве упражнения (Эь).6(2)). 0.3.3. Использование локализаций и фасетов В рамках стандартной библиотеки локализации в первую очередь принимаются во внимание в операциях ввода/вывода. Тем не менее, механизм локализации является общим и расширяемым средством представления информации, чувствительной к локальным и национальным особенностям.
Класс те)залез (Эгэ.4.7) является примером фасета, не имеющего никакого отношения ко вводу/выводу'. Расширения библиотеки потокового ввода/вывода и средства ввода/вывода, не опирающиеся на потоки, также могут использовать объекты 1вса1е. Пользователь может использовать контексты локализации для организации произвольной информации, зависимой от национальных и культурных особенностей. Благодаря общности механизмов локализаций и фасетов возможности определяемых пользователем фасетов не ограничены. Вероятными кандидатами на представление фасетами являются даты, часовые пояса, телефонные номера, номера социального страхования, товарные коды, температурные величины, произвольные пары измеряемых величин (единица измерения, значение), почтовые коды (х)р-коды), размеры одежды и т.д. Как и другие мощные механизмы, фасеты следует применять с определенной осторожностью.
Из одного лишь факта, что нечто может быть представлено в виде фасета, не следует, что такое представление будет наилучшим. Для выбора ключевыми, как и всегда, являются следующие факторы: как различные решения влияют на сложность написания кода, легко или сложно читать этот код, насколько сложно поддерживать код в дальнейшем в процессе его эксплуатации и неизбежных модификаций, какова эффективность операций ввода/вывода в плане быстродействия и используемой памяти.