Выбрать главу

Табл. 10.1. Текстовые манипуляторы

Манипулятор Описание Пример вывода
left right Выровнять значения в текущем поле вправо или влево, заполняя незанятое пространство символом-заполнителем Выравнивание влево apple      banana     cherry     Выравнивание вправо (ширина поля 10)      apple     banana     cherry
setw(int n) Установить размер поля на n символов См. предыдущий пример
setfill(int с) Использовать символ с для заполнения незанятого пространства поля cout << setfill('.') << setw(10) << right << "foo" Выдает: .......foo
boolalpha noboolalpha Отобразить булевы значения в текущем локализованном представлении слов true и false, а не 1 и 0 cout << boolalpha << true Выдает: true
endl Записать в поток символ новой строки (newline) и очистить буфер вывода Нет
ends Записать в поток null-символ ('\0') Нет
flush Очистить буфер вывода Нет

Некоторые представленные в табл. 10.1 (и в табл. 10.2 в следующем рецепте) манипуляторы переключают бинарные флаги потоков и в действительности реализуются как два манипулятора, которые включают и отключают флаг. Например, возьмем манипулятор boolalpha. Если вы хотите, чтобы булевы значения отображались в соответствии с текущей локализацией (например, «true» и «false»), используйте манипулятор boolalpha. Для отключения этого режима, чтобы вместо слов печатались 0 и 1, используйте манипулятор noboolalpha (он используется по умолчанию).

Действие всех манипуляторов сохраняется до тех пор, пока оно не будет явно изменено, исключая манипулятор setw. Из примера 10.1 видно, что он вызывается перед каждой записью, однако left используется только один раз. Это объясняется тем, что ширина поля устанавливается в нуль после записи каждого значения в поток при помощи оператора operator<<; чтобы обеспечить одинаковую ширину всех полей, мне пришлось каждый раз вызывать setw.

Стандартные манипуляторы позволяют делать многое, но не все. Если у вас возникает потребность в написании собственного манипулятора, см. рецепт 10.2.

Как и все другие классы стандартной библиотеки, работающие с символами, манипуляторы работают с потоками узких или широких символов. Поэтому вы можете использовать их в шаблонах для написания утилит форматирования, обрабатывающих потоки символов любого вида. В примере 10.2 приводится шаблон класса TableFormatter, который форматирует данные в колонки одинаковой ширины и выдает их в поток.

Пример 10.2. Параметрический класс для табличного представления данных

#include <iostream>

#include <iomanip>

#include <string>

#include <vector>

using namespace std;

// TableFormatter выдает в поток вывода символы типа T в форматированном

// виде.

template<typename T>

class TableFormatter {

public:

 TableFormatter(basic_ostream<T>& os) : out_(os) {}

 ~TableFormatter() {out_ << flush;}

 template<typename valT>

 void writeTableRow(const vector<valT>& v, int width);

 //...

private:

 basic_ostream<T>& out_;

};

template<typename T, // ссылается на список параметров шаблона класса

 typename valT>      // ссылается на список параметров функции-члена

void TableFormatter<T>::writeTableRow(const std::vector<valT>& v,

 int width) {

 ios_base::fmtflags flags = out_.flags();

 out_.flush();

 out_ << setprecision(2) << fixed; // Задать точность в случае применения

                                   // чисел с плавающей точкой

 for (vector<valT>::const_iterator p = v.begin(); p != v.end(); ++p)

  out_ << setw(width) << left << *p; // Установить ширину поля, его

                                     // выравнивание и записать элемент

  out_ << endl; // Очистить буфер

 out setf(flags); // Восстановить стандартное состояние флагов

}

int main() {

 TableFormatter<char> fmt(cout);

 vector<string> vs;

 vs.push_back("Sunday");

 vs.push_back("Monday");

 vs.push_back("Tuesday");

 fmt.writeTableRow(vs, 12);

 fmt.writeTableRow(vs, 12);

 fmt.writeTableRow(vs, 12);

 vector<double> vd;

 vd.push_back(4.0);

 vd.push_back(3.0);

 vd.push_back(2.0);

 vd.push_back(1.0);

 fmt.writeTableRow(vd, 5);

}

Вывод представленной в примере 10.2 программы выглядит следующим образом.

Sunday     Monday      Tuesday

4.00 3.00 2.00 1.00

Смотри также

Таблица 10.1, рецепт 10.2.

10.2. Форматирование вывода чисел с плавающей точкой

Проблема

Требуется выдать числа с плавающей точкой в удобном формате либо ради обеспечения необходимой точности (применяя нотацию, которая используется в науке, а не в виде числа с фиксированной точкой), либо просто выравнивая значения по десятичной точке для лучшего восприятия.

Решение

Используйте стандартные манипуляторы, определенные в <iomanip> и <ios>, для управления форматом значений чисел с плавающей точкой при их записи в поток. Это можно делать очень многими способами, и в примере 10.3 предлагается несколько способов отображения значения числа «пи».

Пример 10.3. Форматирование числа «пи»

#include <iostream>