Программирование >>  Разработка устойчивых систем 

1 ... 44 45 46 [ 47 ] 48 49 50 ... 196


: C04:InputWidth.cpp

Ограничения при использовании setw с потоками ввода

#1nclude <cassert>

#1nclude <cmath>

#1 ncl ude <iomamp>

#include <limits>

#1nclude <sstream>

#1nclude <string>

using namespace std:

int mainO { istringstream isCone 2.34 five ): string temp: is setw(2) temp: assert(temp == on ): is setw(2) temp: assert(temp == e ): double x:

is setw(2) x:

double relerr = fabs(x - 2.34) / x:

assert(relerr <= numeric limits<double>::epsilon()):

} III:-

При чтении строк функция setw() будет успешно управлять количеством прочитанных символов... до определенного момента. При первом чтении будут получены два символа, а при втором - только один, хотя мы запрашивали два. Дело в том, что операторная функция operator () использует пропуски как ограничители ввода (хотя с этим можно бороться, сбросив флаг skipws). Но при чтении чисел невозможно ограничить количество читаемых символов при помощи setw(). В случае потоков ввода функция setw() работает только при чтении строк.

Создание манипуляторов

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

ostream& endl(ostream&):

После этого в выражениях наподобие следующего endl интерпретируется как адрес этой функции:

cout howdy endl:

Компилятор спрашивает: Существует ли подходящая функция, в аргументе которой передается адрес функции? Для этого в <iostream> определены специальные функции, называемые аппликаторами. Аппликатор вызывает функцию, полученную в аргументе, и передает ей объект ostream в качестве аргумента. Чтобы создать собственный манипулятор, не нужно разбираться в принципах работы аппликаторов; достаточно знать, что они существуют. Упрощенный код аппликатора ostream выглядит так:

ostreamS ostream::operator (ostream& (*pf)(ostream&)) { return pf(*this):



int mainO { cout newlines nl between nl each nl word nl:

} /:-

При направлении nl в поток вывода (например, в cout) происходит следующая последовательность вызовов:

cout.operator (nl) ® nl(cout)

Показанное ниже выражение внутри п1() вызывает операторную функцию ostream::operator(char):

OS \n:

Поток, возвращаемый этой функций, в конечном счете возвращается манипулятором nl.

Эффекторы

Итак, манипуляторы без аргументов создаются легко. А если вам нужен манипулятор с аргументами? Просматривая заголовок <iomanip>, вы найдете тип smanip, возвращаемый манипуляторами с аргументами. Возникает предположение, что этот тип нужно использовать при определении собственных манипуляторов, но делать этого не стоит. Тип smanip зависит от реализации, а его использование нарушает переносимость программы. К счастью, манипуляторы с аргументами можно определять без применения специальных трюков. Для этой цели Джерри Шварц (Jerry Schwarz) предложил методику, основанную на применении эффекторов. Эффектор представляет собой класс с конструктором и перегруженным оператором . Конструктор форматирует строку, представляющую нужную операцию, а оператор направляет эту строку в поток. Здесь приводятся два эффектора: первый выводит усеченную символьную строку, а второй - число в двоичном виде.

Перед включением nl в заголовочный файл объявите его подставляемой (inline) функцией. Разработчик библиотеки потоков ввода-вывода.

Реальное определение выглядит несколько сложнее, потому что в нем используются шаблоны, но для пояснения достаточно и этого. Когда в поток выводится функция, похожая на *pf (которая получает и возвращает ссылку на поток), вызывается функция-аппликатор. В свою очередь, она выполняет функцию, на которую ссылается pf. Аппликаторы для ios base, basic Jos, basic ostream и basicjstream определены в стандартной библиотеке С++.

Для пояснения сказанного рассмотрим тривиальный пример - манипулятор п1, эквивалентный занесению в поток символа перевода строки (то есть не выполняющий сброс потока, в отличие от endl):

: С04:п1.срр Создание манипулятора linclude <iostream> using namespace std:

ostreamS nl(ostream& os) { return OS \n:



int mainO { string words =

Things that make us happy, make us wise : for (int i = words. SizeO: --i >= 0:) {

ostringstream s:

s Fixw(words, i):

assert(s.str() == words.substr(0. D):

ostringstream xs. ys; xs Bin(OxCAFEBABEUL): assert(xs.str() ==

1100 1010 1111 1110 1011 1010 1011 1110 ); ys Bin(0x76543210UL): assert(ys.str() ==

0111 0110 010Г 0100 00П 0010 0001 0000 ): } III:-

Конструктор Fixw создает укороченную копию своего аргумента char*, а деструктор освобождает память, выделенную для этой копии. Перегруженный оператор берет содержимое своего второго аргумента (объект Fixw), записывает его в свой первый аргумент (ostream) и возвращает ostream для последующего использования в цепочечном выражении. При использовании Fixw в выражениях следу-

: С04:Effector.срр

Эффекторы Джерри Шварца

#include <cassert>

#1nclude <l1mits> Для maxO

#1 nclude <sstream>

#1 nclude <string>

using namespace std:

Вывод префикса: class Fixw { string str; public:

Fixw(const stnng& s. int width) : str(s. 0. width) {} friend ostream& operator (ostream& os. const Fixw& fw) { return OS fw.str:

Вывод числа в двоичном виде: typedef unsigned long ulong:

class Bin {

ulong n; public:

Bin(ulong nn) { n = nn: }

fnend ostream& operator (ostream& os. const Bin& b) { const ulong ULMAX = numeric limits<ulong>::max(): ulong bit = -(ULMAX 1); Установлен старший бит while(bit) {

OS (b.n & bit ? T : 0);

bit = 1:

return OS:



1 ... 44 45 46 [ 47 ] 48 49 50 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика