Использование операторов вставки и управление форматом

В этой статье описывается, как управлять форматом и как создавать операторы вставки для собственных классов. Оператор вставки (<<), который изначально включен во все стандартные типы данных C++, отправляет байты в объект потока вывода. Операторы вставки работают с предопределенными "манипуляторами" — элементами, которые изменяют формат целочисленных аргументов, заданный по умолчанию.

Форматом можно управлять с помощью следующих параметров:

Ширина выходных данных

Чтобы выровнять выходные данные, необходимо указать ширину вывода для каждого элемента, поместив setw манипулятор в поток или вызвав width функцию-член. В этом примере выравниваются по правому краю значения в столбце шириной по крайней мере 10 символов:

// output_width.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

int main( )
{
   double values[] = { 1.23, 35.36, 653.7, 4358.24 };
   for( int i = 0; i < 4; i++ )
   {
      cout.width(10);
      cout << values[i] << '\n';
   }
}
      1.23
     35.36
     653.7
   4358.24

Начальные пробелы добавляются в любое значение шириной менее 10 символов.

Чтобы заполнить поле, используйте fill функцию-член, которая задает значение символа заполнения для полей, имеющих указанную ширину. По умолчанию используется пробел. Чтобы заполнить столбец чисел звездочками, измените предыдущий for цикл следующим образом:

for (int i = 0; i <4; i++)
{
    cout.width(10);
    cout.fill('*');
    cout << values[i] << endl;
}

Манипулятор endl заменяет символ перевода строки ('\n'). Выходные данные выглядят следующим образом:

******1.23
*****35.36
*****653.7
***4358.24

Чтобы указать ширину элементов выходных данных в той же строке, используйте манипулятор setw:

// setw.cpp
// compile with: /EHsc
#include <iostream>
#include <iomanip>
using namespace std;

int main( )
{
   double values[] = { 1.23, 35.36, 653.7, 4358.24 };
   const char *names[] = { "Zoot", "Jimmy", "Al", "Stan" };
   for( int i = 0; i < 4; i++ )
      cout << setw( 7 )  << names[i]
           << setw( 10 ) << values[i] << endl;
}

Функция-член width объявлена в <iostream>. Если вы используете setw или любой другой манипулятор с аргументами, необходимо включить <iomanip>. В выходных данных строки печатаются в поле ширины 6 и целых чисел в поле ширины 10:

   Zoot      1.23
  Jimmy     35.36
     Al     653.7
   Stan   4358.24

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

Точное понимание

По умолчанию выравнивание текста в потоках вывода задано по правому краю. Чтобы выровнять имена в предыдущем примере и выровнять их по правому краю, замените for цикл следующим образом:

for (int i = 0; i <4; i++)
    cout << setiosflags(ios::left)
         << setw(6) << names[i]
         << resetiosflags(ios::left)
         << setw(10) << values[i] << endl;

Выходные данные выглядят следующим образом:

Zoot        1.23
Jimmy      35.36
Al         653.7
Stan     4358.24

Флаг выравнивания слева устанавливается с помощью setiosflags манипулятора left с перечислителем. Этот перечислитель определен в ios классе, поэтому его ссылка должна содержать ios:: префикс. Манипулятор resetiosflags отключает флаг выравнивания слева. В отличие width от и setw, эффект setiosflags и resetiosflags является постоянным.

Точность

По умолчанию для чисел с плавающей запятой задана точность шесть. Например, число 3466,9768 выводится как 3466,98. Чтобы изменить способ печати этого значения, используйте манипулятор setprecision . Манипулятор имеет два флага: fixed и scientific. Если fixed задано, число выводится как 3466,976800. Если scientific задано, он печатается как 3.4669773+003.

Чтобы отобразить числа с плавающей запятой, показанные в выравнивании с одной значительной цифрой, замените for цикл следующим образом:

for (int i = 0; i <4; i++)
    cout << setiosflags(ios::left)
         << setw(6)
         << names[i]
         << resetiosflags(ios::left)
         << setw(10)
         << setprecision(1)
         << values[i]
         << endl;

Программа выведет этот список:

Zoot          1
Jimmy     4e+01
Al        7e+02
Stan      4e+03

Чтобы исключить научное нотацию, вставьте следующую инструкцию перед циклом for :

cout << setiosflags(ios::fixed);

С фиксированной нотацией программа выводит числа с одной цифрой после десятичной запятой.

Zoot         1.2
Jimmy       35.4
Al         653.7
Stan      4358.2

Если вы измените флагios::scientific, программа выводит следующееios::fixed:

Zoot    1.2e+00
Jimmy   3.5e+01
Al      6.5e+02
Stan    4.4e+03

В этом случае программа также выводит числа с одной цифрой после десятичной запятой. ios::fixed Если задано значение ios::scientific точности, оно определяет число цифр после десятичной запятой. Если не установлен ни один из флагов, значение точности определяет общее количество значащих цифр. Манипулятор resetiosflags снимает эти флаги.

Основание системы счисления

Для decocthex ввода и вывода манипуляторы задают радикс по умолчанию для входных и выходных данных. Например, при вставке манипулятора hex в выходной поток объект правильно преобразует внутреннее представление целых чисел в шестнадцатеричный выходной формат. Числа отображаются с цифрами f в нижнем регистре, если uppercase флаг очищается (по умолчанию); в противном случае они отображаются в верхнем регистре. По умолчанию радикс имеет значение dec (десятичное).

Строки в кавычках (C++ 14)

При вставке строки в поток можно легко получить ту же строку обратно, вызвав stringstream::str() функцию-член. Однако если вы хотите использовать оператор извлечения для вставки потока в новую строку в более позднюю точку, может возникнуть непредвиденный результат, так как >> оператор по умолчанию остановится при обнаружении первого символа пробела.

std::stringstream ss;
std::string inserted = "This is a sentence.";
std::string extracted;

ss << inserted;
ss >> extracted;

std::cout << inserted;     //  This is a sentence.
std::cout << extracted;    //  This

Эту проблему можно устранить вручную, но чтобы сделать обход строки более удобным, C++ 14 добавляет манипулятор потока std::quoted в <iomanip>. После вставки quoted() окружает строку разделителем (двойным кавычки " по умолчанию) и при извлечении потока выполняется обработка потока для извлечения всех символов до тех пор, пока конечный разделитель не найден. Все внедренные кавычки экранируются с помощью escape-символа ('\\' по умолчанию).

Разделители присутствуют только в объекте потока; Они не присутствуют в извлеченной строке, но они присутствуют в строке, возвращаемой basic_stringstream::str.

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

Дополнительные сведения и полные примеры кода см. в разделе quoted.

См. также

Потоки вывода