Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 222
Текст из файла (страница 222)
5678 « ' ~п'; На выходе получим: в!у!е А: 12345678 *** 1234. 5678 вб1е В: 12 345 678 *** 1 234,5678 Заметьте, что ипЬие () хранит копию своего аргумента в своем потоке. Следовательно, поток может использовать прикрепленную к нему локализацию даже после того, как ее оригинал будет уничтожен. Если !ое(геит имеет установленный флаг Ьоо1а1рйа (82!.2.2, 521.4.1), то для символьного представления иие иУа(ее использу- 0.4. Стандартные фасеты 1035 ются возвраты функций сгиепате() и 1асзеиате(), соответственно; в противном случае используются 1 и О. Имеется и соответствующая Ьуаате версия для питрипсс 51>.4, вО.4.!): сетр!асе<с1азз СЬ> с1ат зЫ:: питрипсс Ьупате: риЫ(с литрипсс<СЬ> ( /*...
*/ ); О.4.2.2. Вывод чисел При записи в буфер потока (й2!.б.4) озсгеат использует фасет липс рил сетр1асе<с!ат СЬ, с!ат Оис = озсгеатЬи1 1(егасог<СЬ» с!азз зЫ:: пит рис: риЫ(с !оса!е: саве! ( риЬНс: (урезе~ СЬ сЬаг суре! (урез(е1' ОШ Нег Суре; ехрпсН пит рш (з!се с г = д) з /поместить значение "г" в позицию буфера "Ь" потока "з": Оис рш(Ош Ь, соз Ьазеь з, СЬЯН, Ьоо! г) солт; Оисрш(Оис Ь, юз Ьазеь з, СЬ1)Н, !оле г) сопи; Оис рис(Оис Ь, юз Ьазеь з, СЬ11Н, илз1елез(1оле г) сопл!; Ош рис(Оис Ь, юз Ьазеь з, СЬяН, з(оиЫе г) сопл!; Оис рис(Оис Ь, юз Ьазеь з, СЬ1)И, !она з(оиЫе и) сопл!( Ош рис(Ош Ь, !оз Ьазеь з, СЬ !Ш, соле! иоЫ* г) сопл!; зсабс !овесе:: Ы Ы; /обьект идентификации фасета ДР.2 3Р.3,ь(Р.3.!) ргосессеб: -литл рис(); Р виртуальные гбо "-функции (см. ЬР.4.!) )' Аргумент Оис (итератор вывода; з)9.
1, в)9.2. !) идентифицирует место в буфере потока озсгеат (з2 !.6.4), в которое рис( ) помещает символы, представляющие выводимое числовое значение. Возврат функции рис() — это итератор, указывающий на позицию, следующую за последним записанным символом. Отметим, что умолчательная специализация пиит рис (та, чей итератор для доступа к символам имеет тип озсгеатЬи~ Негаюг<СЬ>) является частью стандартного контекста локализации (йО.4). Если вам нужна иная специализация, придется создать ее самостоятельно. Например: гетр!осе<с!от СЬ> сЫт Яппд писари!: риЫзс зсб:: лит рис<СЬ, сурепате Ьаз!с зсгсле<СЬ>:: Негасог> ( риЬНс: Бсппе питрис(): зас::питрис<СЬ, сурепате Ьаяс зсг!пе<СЬ>::1(егасог> (1) ( ) ): // форматирование 1 в з с позиции роз гоЫ1(!асс', зсг1леь з, 1псроз) ( Бэппа питриС<сЬаг> 1/ юз Ьазеь ххх = сои!( //используем правила форматирования потока сош 1рш(з.Ьее!п () +роз,ххх, ' ',!) с /форматируем !в з 1036 Приложение ().
Локализация Аргумент 1ов Ьазе используется для получения информации о состоянии форматирования и локализации. Например, если требуется осуществить заполнение определенного пространства, используется символ у211, как того требует аргумент 1ол Ьазе. Как правило, буфер потока, в который пишут через итератор Ь, является буфером, ассоциированным с ол(геат, для которого в является базовым классом. Заметим, что сконструировать объект типа 1ов Ьазе не просто. Он, в частности, управляет множеством аспектов форматирования, которые нужно согласовывать с целью достижения приемлемого вывода. Соответственно, в йм Ьате нет открытого конструктора (521,З.З).
Функция риг () также пользуется аргументом 1аа Ьате для доступа к локализации потока. Она используется для определения пунктуации (9Э.4.2.1), символьного .представления булевых значений и для преобразований к Сй. Например, если з является аргументом типа 1оз Ьаве у функции рис(), то в исходном тексте этой функции можно было бы встретить следующие фрагменты кода: солт 1оса1еа 1ос = в.ае(1ос (); И.. юсйаг г ю = иве Тасс(<с(уре<сйаг» (1ос) . вЫеп (с); И из сйог в Сй И... впчп8 рог = иве Тасег<питрипсг<сйаг» (1ос) .лес(та1 ро1п((); д по умолчанию: '.' И... впчпа Иве = иве ~асег<питрипсг<сйаг> > (1ос) .уа1лепате (); И по умолчанию: 'то(ве" Стандартные фасеты, такие как пит рит<сйаг>, обычно используются неявно в функциях стандартного ввода/вывода; поэтому большинству программистов нет необходимости знать о них.
Тем не менее, использование таких фасетов стандартными библиотечными функциями представляет интерес, поскольку иллюстрирует работу потоков ввода/вывода и способы обращения с фасетами. Как всегда, стандартная библиотека демонстрирует примеры интересных программных технологий. Используя пигп риб разработчик озггеат мог бы написать: гетр)а(е<с(ат Сй, с1авв Тг> отгеата вЫ:: Ьавгс овггеат<Сй, Тг>::орегагог« (ИоиЫе И) ( лепау аиагл(*гйгв) ч И см.
з21.3.8 Д'(!8иагл) ге(ига *ей(в; ( (Т( иве та<ее<пот рие<СЬ» (яецос ( ) ) . риг (*гйгв, *ей(в, сщв — >1)И( ), а) .~алел ( ) ) вееааге (Ьаг(ЫЬ) ч ) сагой (... ) ( йапйе (оелсердоп ("гй(л); ) ге<ига *ей(л; В этом примере много интересного. Класс веп(гу (часовой) обеспечивает гарантию выполнения всех префиксных и постфиксных операций (521.3.8). Мы получаем контекст локализации потока атегеат вызовом его функции-члена ает1ос() (3.4. Стандартные фасеты 1037 (521.7). Извлекаем иит ри< из!оса!е при помо<ци изе Тасе< (5Р.3.1). После этого мы обращаемся к соответствующей функции ри<() для выполнения реальной работы.
Итератор озггеатЬиу Иегаюг можно сконструировать из ози еат (519.2.6), а оя<геат можно неявно преобразовать к его базовому классу юя Ьазе (921.2.! ), чтобы обеспечить два первых аргумента лля функции ри<() . Функция ри<() возвращает свой аргумент, являющийся итератором вывода. Этот итератор вывода извлекается из Ьая(с аз<геат, так что он имеет тип оз<геатЬиУ Иега<ог. Следовательно, для проверки корректности состояния и для установки такого состояния нам доступна функция 1аИе<1 О (519.2.6.1).
Я не использую ияе ~асе<, поскольку гарантируется, что стандартные фасеты (5Р.4) присутствуют в любом контексте локализации. Если эта гарантия нарушается, генерируется исключение Ьа<1 сия< 5Р.З.!). Функция ри<() вызывает виртуальную функцию <(о ри<(), так что может быть задействован пользовательский код и орега<ог«() должен быть готов к обработке исключения, генерируемого замещающим вариантом й» ри<(). Кроме того, иит ри< может отсутствовать для некоторых символьных типов, так что ияе гасе<() может сгенерировать исключение зи1:: Ьа<1 саз< ЯР.3.1).
Поведение операции «для встроенных типов, таких как <1оиЫе, определено стандартом языка С++. Стало быть вопрос не в том, что должна делать функция Ьаи<Ие юехсериои (), а в том, как она должна действовать в соответствии со стандартом. Если в исключении у оз(геа<п установлен флаг ЬаИЬИ (52! .3.6), то исключение просто повторно генерируется.
В противном случае обработка исключения сводится к установке состояния потока и продолжению работы. В обоих случаях нужно установить флаг Ьа<161< (з21.3.3): <етр1а<е<с!азз СЬ, с1азз Тг> гоЫ ЬвлМе 1оехсербол (зи(: <Ьаз(с отгеат<СЬ, Тг>а з) У вызывается из со<с(«бяока ( <1(з.
ехсер<(олз ( ) а юз базе «Ьа<(Ь«) ( оу ( з. зеоив<е (<оз Ьвзе:: Ьа<(Ьи) < д может гелер-вать Ьо»1с (оз:.)а<(иге са<сЬ(... ) () <Ьго»в < з.зета<в (1оз Ьвяе::Ьваь!<)» ) (< повторная генерация искяючения Здесыгу-блок необходим, поскольку яеша<е() может сгенерировать исключение Ьая(с юз:: 1а11иге (521.3.3, 521.3.6). Однако если в исключительном состоянии потока установлен флаг ЬаИЬИ, тогда орегаюг«() должен повторно сгенерировать исключение, приведшее к вызову ЬатИе 1оехсериои() (а не просто сгенерировать Ьаяс юя«ТаИиге). Реализация операции «для встроенных типов, таких как <(оиЫе, должна писать непосредственно в буфер потока.
Реализуя операцию «для пользовательских типов, мы можем избежать ненужной сложности путем сведения вывода пользовательских типов к выводу уже существующих типов ЦР.3.2). Приложение Р. Локализация 1ОЗВ 0.4.2.3. Ввод чисел При чтении из буфера потока (521.6.4) !зятеат полагается на фасет пит Вер.
гетр!аге<с!ат СЬ, с1ат 1п = (зггеатбьу Оегагог<СЬ» е!азз яЫ:: питбез: риЫгс !оса!е::)асе1 ( риЫ1с: (урейер СЬ сваг гуре! (урейе11п пег гуре! екрпсй пит де1 (з!ье 1 г = 0) 1 ~У читаем !Ь:е) в г по провизии форматирования из з; об ошибках - через г: 1и без(1п Ь, 1п е, юз Ьазеь з, !оз Ьазе::1оз(агеь г, Ьоо1ь г) сопя(1 1п бег(1п Ь, 1п е, 1оз Ьазеь з, !оз Ьазе::юз1агеь г, !опяь г) сопя! 1п яе1(1п Ь, 1и е, юз Ьазеь з, !оз базе::!озгагеь г, ииз!8пеб завяз г) сопя! 1п яе1(1п Ь, 1и е, гоз Ьазеь з, юз Ьазе::!озгагеь г, ииз!8пеб !игь г) сопя!1 1п без(1п Ь, 1и е, юз Ьазеь з, !оз Ьазе::!ояа(еь г, ииз!8пеб!опяь г) сопя(; 1и бег(1п Ь, 1п е, (оз Ьазеь з, !оз Ьазе::!озгагеь г, 3!оагь г) сопя; 1п де!(1п Ь, 1и е, !оз Ьазеь з, юз Ьазе::!озгагеь г, боиЫеь г) сопя(1 1и 8е1 (1п Ь, 1и е, юя Ьазеь з, юя Ьазе::!оя(а(еь г, !оия йоиЫеь г) сопя!; 1п бег(1п Ь, 1п е, юз Ьазеь з, юз Ьазе::юяа1еь г, гоЫ*ь г) сопз11 ззабс !оса!е::Ы Ы; У обьект идентификации фасета ЯР.2, яР,3, яР.З.!) ргогесгеб: -иит лез() 1 й' виртуальные )(о "-функции !см.
3Р.4. !) )1 В основном иит пег() реализован так же, как и пит риз 5О.4.2.2). Поскольку лез() читает, а не пишет, то ей нужна пара итераторов ввода, а аргумент, обозначаюший целевой объект для читаемых данных, представлен ссылкой. Для уведомления о состоянии потока устанавливается переменная г типа зояаге. Если значение желаемого типа прочитать не удается, то флаг)а!1Ы1 в переменной г устанавливается; если был достигнут конец ввода, то в г устанавливается еой)1(.