Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 225
Текст из файла (страница 225)
И все-таки, как и большинство специальных нотаций, эта форма записи решает задачу и часто даже удобна. Кроме перечисленных директив форматирования, болыпинство реализаций поддерживают нмодификаторы»ч например целые, указывающие ширину поля (9 21.8), %!ОХ Модификаторы форматов дат и времени не являются частью стандарта С+~, но стандарты некоторых платформ, например РОЯ!Х, требуют их. Поэтому трудно избежать применения модификаторов, хотя их использование не полностью перепосимо. Подобная врг(п1/Я 21.8) функция в1ф(тв() из <с!!те> плн с!!те Ь> осуществляет вывод с использованием директив форлсатирования времепи и дат: и!вв ! в1г/1!япв(сдаг' в, в!гв 1 япак, свпв1 сваг'/огтаг, свпв! 1т* гтр); Эта функция помещает максимум тах символов из *1тр и/оста! в *з.
Например: Ьа1таяп() ( сйаг ЬиЯ20) // небрежно: надежда на то, нтов1фгтв () // накогда нв вернет более 20 силввлов пте 1!= Оняе(0); вггЯгпв(ЬиЯ 20, %ЛЯ,п', !оса!1!тв(с 1)); сваг «Ьи/. В среду результатом вывода будет Ведпввс(ау в локализации по умолчанию с(авв(с() Ц Г.2.3) и опас/ад в датской локализации. Символы, не являющиеся частью задаваемого формата, такие как перевод на новую строку в примере, просто копируются в первый аргумент (в). Когда ри1() обнаруживает символ форматирования/(и необязательный модификатор т), для реального выполнения форматирования она вызывает виртуальную функцию с(о ри1() с соответствующими параметрами: Ыо ри1(Ь, в, фИ, 1,/ т).
Вызов ри1(Ь, в Я11, 1,/', т) является упрощенной формойри1(), где символ форматирования Щ и символ модификатора (т) заданы явно. Таким образом, вызов согяв! сЬаг/тг() = ";6!ОХ'; рис(Ь, в, /111, 1,/т1,/т1 +вива/(/тг)) можно сократить; ри!(Ь, в, 11!1, 1, 'Х', !О); Если формат содержит многобайтные символы, он должен и начинаться, и заканчиваться в состоянии по умолчанию (9 Г.4.8).
Мы можем воспользоваться ри1(), чтобы реализовать зависящий от локализации оператор вывода для 2!а1е: 991 Г4, Стандартные фасеты ое!геат8, орега!ог ~)ое!геата е, сапе!/эа!ей с!) 1 оеиеатсееппу уиагс!)е), //ся. 9 21.3.8 сЯаиагф ге!игл е, !и' !тр = !оса!!!те)йсЫ~; !гу ( Яиее ~асс!с!!те ри! -сЬаг»)е.уе!!ос))).ри!) и, е, еЯ!1)), !тр, 'х')/а!!ег!))) е.ее!е!а!е)!ое Ьаее../а!!Ь!!); са!сЬ) ...) 1 Ьапг!!е !оехсер!!оп(з) // ся, 9 1 4 2 2 ге!игп еч ) Ввиду отсутствия стандартного типа 1)а!е, отсутствуез н форма ввода/вывода дат по умолчанию.
В примере я задал формат %х путем передачи символа 'х' в качестве символа форматирования. Формат %х является форматом по умолчанию для яе! !!те() Я ГА.4А), так что ничего еболее стандартного», верояпю, и не придумать. См. в 9 Г.4А.5 пример использования альтернативных форматов.
Кроме того, имеется и Ьупате версия Я Г.4, 9 ГА.1) функции !!те рий !етр!аге с!аееСЬ, с)азе Оиг = ое)геатЬи2" !!ега!о~ СЬ» с!аее еЫс!!те ри! Ьупате. риЬ1!спте ри!<СЬ, Ои1>1/' ... *,! ); Г.4.4.4. Ввод дат и времени Как всегда, ввод сложнее вывода. При написании кода для вывода значения часто имеется выбор из различных форматов. Л прн написании кода для ввода мы еще должны уметь обрабатывать ошибки и решать, с каким пз нескольких возможных форматов мы столкнулись. Фасет !!те де! реализует ввод дат и времени.
Идея состоит в том, что !!те Ье! конкретной локализации может читать время и даты, выведенные !!те ри! этой же локализации. Однако ввиду отсутствия стандартных классов даты и времени, программист может воспользоваться локализацией для вывода в соответствии со множеством форматов. Например, все следующие представления могут быть получены при помощи единственной инструкции вывода с использованием !!те ри! Я Г.4.4.5) различных локализаций: Запиагу 15!Ь 1999 ТЬи~Ыау 16!Ь 1апиагу 1999 15./ап 1999АО Т1низ ! 5/1/99 Стандарт С++ поощряет разработчиков !!те ге! воспринимать форматы дат и времени в соответствии с РОЯ)Х и другими стандартами. Проблема состоит в том, что сложно стандартизовать потребность в чтении дат и времени во всевозможных форматах, принятых в рамках данной культуры.
Полезно поэкспериментировать, чтобы узнать, что предоставляет данная локализация Я Г.6)8)). Воли формат не воспринимается, программист может реализовать подходящий альтернативный фасет !!те де!. Приложейие Г Локализация 992 Стандартный фасет ввода времени 1!те уе1 является производным от йте базе: Разработчик может воспользоваться этим перечислением для упрощения разбора форматов даты. Подобно пит дед функция йте уе1 осуществляет доступ к своему буферу при помоьчи пары итераторов ввода; 1етр!аге <с!аяя СЬ, с1аяя 1и = 1з1 еатЬц/ йега1ог<СЬ» с!азя йте уе1. риЫ1е!оса!вуасе1, риЫ!с йте Ьаяе ( риЬйс: 1урейе/' СЬ сйаг суре, 1урейе/1п йег 1уре; ехрйслй йте уес(я/яе 1г=б) йа1еогйегйа1е огйег() сопя!(ге1иги йо йа1е огйел() ) // чтение /Ь,е) в д с испояьзованиелл правил форллаилирования из.я и сообщением // об ошибке путелл усгпановки и !п де1 1ипе(йл Ь, 1п е, ьоя Ьаяе& я, юя Ьаяеп!оя1а1е& г, 1т* й) сопя!; !п уе1 йаге(!п Ь, 1п е, !оя Ьаче& я, юя Ьаяа:!ояса1е& г, 1т' й) сопя!; 1и уе1 уеал(1п Ь, !п е, !оя Ьаяе& я, !оя Ьаяесюя1а!е& г, 1т* й) сопя!; 1п де1 илееуйау(1лл Ь, !п е, !оя Ьазе& я, юя Ьаяе.лоя1аге & г, Пп* с!) сопя1, 1п уе1 топсйпате(1п Ь, 1п е, лоя Ьаяе& я, юз Ьаяе:юзса1е& г, 1т* й) сопяб я1а11с!оса!епгй !й; // идентификатор фасета (Я !".2, з !'.3, з !:3.! ) рга1ес1ей: -йте уе1(); // впртуальние 'йо функции' Гсм.
у Л4.!) Функппя уе1 Йте() вызывает йо де! йте(), По умолчанию уе! йте() читает время, как оно выводится йте ри1при1() данной локализации с использованием формата'/Х (9 ГАА). Точно так же функция яе1 йа1е() вызывает йо уе1 йа1е(). По умолчанию, уе! йа1е() читает дату так, как она выводится йте ри1сри1() данной локализации с использованием формата '/х (9 ) АА). Таким образом, простейший оператор ввода для Ра1е выглядит примерно так; !ясгеат & орега1огь' ',ья1геат & я, лла1е& й) ( !я! геат ..яеп 1гу уиагй(я) // см, ~ 2 1. 3, 8 с!аяя зсйп11те Ьаяе ( ри Ьйс.
епит йа1еогс!ег ( по огйег, йту, тйу, утй, уйт // не упорядочено; возлложно, л~ного элементов // (таких как день недесли) // день — л~есяц — год // месяц — день — год // год — месяц — день // год — день — месяц 993 Г4. Стандартные фасеты тЯуиагс/) ге1игп я; !оя Ьаяес(оятасе гея = 0; стх=(0); !я1геатЬиу цега1ог сааг, сааг 1га!1я<сдаг» епс); сгу ( ияе /асе1<пте дегчсдаг»(я.уе11ос()).уе! да1е(я, елс),я, гея, 1,х); са!сд(...) ( Ьапс/1е !оехсер!1ол(яй // см. 9 Г.4.2,2 ге1игп я, ) с/= 1!псе(хссл тс/ау, 1ха1е:.Мосс!6(х1т топ+1), х ст уеаг+1900); ге1игп я; Вызов де! сса1е(я, елс(, я, гея, 8х) полагается на два неявных преобразования из сяггеат: в качестве первого аргумента, я используется для создания сяггеатби/ 11ега1ог, в качестве третьего аргумента, я преобразуется в базовый класс 1оя Ьаяе.
Этот оператор ввода будет корректно работать с датами из диапазона, представимого 1!те 1. Г! ример тривиального теста: исс тиса() сгу ( Ва1е гос!ау; сои1 «1ос/ау «епс/1; Ва1е с/( 12, /ха сеет ау, 1999); // запись в формате ',4х сои1 «с( «елс11; Васе сЫ; ю61(е(ссл» с!с!) сои!«сЫ «елс/1; // чтениедат вформате %х са1са (/ха1есВас/ с/а1е) ( сои1 « "выход: неправильнал дата~л'; Имеется и Ьулатеверсия Я Г.4, 9 ГАА) функции!!те уе1: !етр1а1е <с1аяя СЬ, с!аяя 1п = !я!сватьи/ !1ега1ог<СЬ» с1аяяясс/сс!те уес Ьупате: ри61!сите уе1чСИ,Ьс>(/'... */); Г.4.4.5.
Более гибкий класс С!н!е Попытка воспользоваться 21а1е из 9 Г.4А.2 с вводом/выводом из 9 ГА.4.3 и сс ГААА вскоре выявила бы ограниченность класса 1)а1е: [1) Он работает только с датами, представимыми в форме 1!те 1, что как правило означает диапазон (1970, 2038). (2) Он воспринимает даты только в стандартном формате — каким бы тот н!и был.
) 3] Его реакция на ошибки ввода неприемлема. )4) Он поддерживает только потоки сйаг (а не потоки произвольных символьных типов). Более интересный и полезный оператор ввода должен воспринимать более широкий диапазон дат, распознавать несколько распространенных форматов, надежно и со- Приложение П Локализация 994 держательно сообщать об ошибках. Для достижения этих целей нам придется рас- статься с 1!те б с1аээ Ра1е ( риЫ(с влит Мол!/л ((ап=1,~еЬ, таг, арг, тау, /ип,/и1, аиу, вер, ос1, лоо, с(ес); Игис1Вай йа!е ( солИ сяаг' т/лу; // в чем прей<ел!а у Вай йа1е(сопИ сдаг' р) ' тйу(р) ( ) Раге(Ы1лЫ, Минул тт, ий уу, (л1 йау о/ хоев/с = О); Расе(); иоЫ та/се 1т(1т* !) сопв1; // пол~естить !лп-представление Ра1е в *1 Вте ста/се !иле 1() сопИ; //возвратить!!пле 1-представяениеРа!е ий уеаг() соле! ( ге!игл у; ) Моп!Б топ1Ь() сопв1 ( ге1игл т; ) 1лсйау() соле!( ге!игп й; ) 0-. рпоапн суаг с1; Моп1Ь т; Ы1 у; ); Для простоты я вернулся к,представлению (й, т, у) (9 (0.2).
Конструктор можно определить следующим образом: Ра1есРп1е(т! йй, Мол!!! тт, т1 уу, т1 йау о/ шееу): фЫ), т(тлл), у(уу) фй==О && т==Мол11л(О) && у==0) ге1игп; // Ро1е(0,0,0) являе тся 'нулевой // далпои'" (/(тт</ап)) йес<тт) 1ЬгоилВай йаге("недопустимый номер меся!(а'), (/(йй<1)) &1<сЫ) // сяитхол!упрощенно; см. ф 10.3.! ЙготВай йасе('недопустимое число~! 1~(йау о/ свесу && йау !и шее/е(уу, тт, йсд!= йау о/ илее/с) 1БгоилВай йа1е("недопустимый день недели ), Ра1есРа1еЦ: й(О), т(О), у(0) ( ) //"нулевая дпта" Алгоритм йау Ы шее/с() (день недели) нетривнален и не имеет непосредственного отношения к механизмам локализации, поэтому я оставил его за п(леделами книги.
Если вам нужен этот алгоритм, он наверняка отыщется где-нибудь в вашей системе. Для типов наподобие Ра1е всегда полезно располагать операциями сравнения: Ьоо( орега1ог — =(сопэ1Ра1е& х, солв1 Ра1е& у) ( гешгл х.усам==у.увал() && х.топ!у'~==у топ1Ь() && х.йау()==у.йау(); ) 995 Г4. Стандартные фасеты Ьоо1 орега1ои=(соля1Ра1ей х, сопя1 Ра1ей у) ( ге!игл '(х==у)! ) Поскольку мы расстались со стандартньеми форматами Ет и 1!те 1, нам потребуются функции преобразования для взаимодействия с программами, которые ожидают эти типы: оо!д Ро1е:таье Ееп(1т" р) сопя! // поместить дату в *р ( 1т х = ( 0 ); 'р=х; р->Ет уеаг= у — !900; р — >Ет ееедау= д; р — >1т >пол =т — !; силе еРаее>елаье пте 1() соля1 (/(у<!910)) 2028<у) // упрощенна 0 вариант ЕЬгот Вас! Йаее('дата находится «не диапазона 1ипе 1'); 1тх, таЬе 1т(йх); ге1игл тЬВте(йх); Г.4.4.6.