Манипулатори на потоците в C++

В предишния урок разгледахме концепцията за потоците. Сега ще разгледаме различни форматиращи функции прилагащи контрол във всички видове потоци.

Какво е манипулатор на потока?

Когато започнем да работим по – сериозно с вход и изход в C++, рано или късно стигаме до момент, в който стандартния cout не е достатъчен. В C++ работим с операторите „>>“ или „<< „. Това не е нещо сложно. Това са функции. Първата чете, а втората пише фундаментни типове данни в потока.

Манипулаторът е специална функция в C++, която се използва с входно / изходни потоци (като cin, cout), за да промени начина, по който данните се показват или четат. Можем да използваме манипулатори, когато искаме:

  • форматиране на числа;
  • задаване на точност (десетични знаци);
  • подравняване на текст;
  • промяна на числовата основа (като десетична в шестнадесетична);
  • контролно на разстоянието (извеждане на информация в табличен вид);

Манипулаторите са дефиниране в библиотеката <iomanip>. Taka, че трябва да я добавите във файла където ще използвате манипулаторите.

В изходния си код се очаква да подредите кода си така: че след месеци отсъствие да можете да го прочетете. Отделете операторите. Дайте отстояние на кода който прави действие.

Това е важно не само за вас, а за всеки четящ кода ви. Операторите „<<“ и „>>“ може да объркат всеки.

std::endl

Със сигурност това е най – ползвания манипулатор. Той прави две неща:

  • Записва в буфера на потока знака ‘\n’ (символ за нов ред);
  • Извиква метода на потока flush();

Това добавя знака за нов ред и незабавно изпразва бувера на потока към където потока е закачен. Това обикновено е текстовия изход в терминала. Но може да е файл, или нещо друго. Работи само с изходни потоци. Може би се досещате, че действието му е еднократно.

std::string a {"First line"};
std::string b {"Second line"};

std::cout << a << std::endl;
std::cout << b << std::endl;

std::flush

Само изпразва бувера на потока към дестинацията. Действа еднократно в изходни потоци. В долната програма го показваме. Функцията sleep() кара програмата да заспи за 5 секунди.

#include <iostream>
#include <iomanip>
#include <thread>  // sleep()
#include <chrono>  // sleep()

void sleep() {
    std::this_thread::sleep_for(std::chrono::seconds(5));
}

int main() {
    std::string a {"First line"};
    std::string b {"Second line"};
    
    std::cout << a << '\n' << b << '\n';
    
    sleep();
    std::cout << std::flush;
}

Моя компилатор (macOS) не работи както очаквах 🙂 Изпразва бувера при ‘\n’ 🙂

std::dec, std::hex, std::oct

Тези манипулатори променят потока за постоянно. В долния пример cin приема шеснайсетични числа. А cout ги извежда в десетичен вид.

#include <iostream>

int main() {
    int x {}, y {}, z {};
    
    std::cout << "Въведете три 16 - тични числа: 0x...." << std::endl;
    // std::dec -> std::hex
    std::cin >> std::hex;
    std::cin >> x >> y >> z;
    
    // по подразбиране изхода е std::dec (десетично)
    std::cout << "Десетични стойности:" << std::endl;
    std::cout << "x = " << x << std::endl;
    std::cout << "y = " << y << std::endl;
    std::cout << "z = " << z << std::endl;
}

Ако въведете:

0xFF
0xff 
ff

Резултата ще е:

x = 255
y = 255
z = 255

std::ends

Това добавя ‘\0’ в буфера. И почти не се използва в днешни времена.

std::showbase и std::noshowbase

Показват или скриват префикса на базата: осмични и шестнайсетични числа.

Показване на базата:

#include <iostream>
#include <iomanip>

int main() {
    int const MAX_BYTE {255};
    std::cout << "decimal: " << std::showbase << std::dec << MAX_BYTE << std::endl;
    std::cout << "octal: " << std::showbase << std::oct << MAX_BYTE << std::endl;
    std::cout << "hexdecimal: " << std::showbase << std::hex << MAX_BYTE << std::endl;
}

Изход:

decimal: 255
octal: 0377
hexdecimal: 0xff

Скриване на базата (префикса): noshowbase

#include <iostream>
#include <iomanip>

int main() {
    int const MAX_BYTE {255};
    std::cout << "decimal: " << std::noshowbase << std::dec << MAX_BYTE << std::endl;
    std::cout << "octal: " << std::noshowbase << std::oct << MAX_BYTE << std::endl;
    std::cout << "hexdecimal: " << std::noshowbase << std::hex << MAX_BYTE << std::endl;
}

Изход:

decimal: 255
octal: 377
hexdecimal: ff

std::showpos, std::noshowpos

Тези манипулатори вкючват / изключват знака ‘+’ в изхода. Превода е нещо като „show positive values„.

#include <iostream>
#include <iomanip>

int main() {
    int theLifeValue {42};
    std::cout << "showpos: " << std::showpos << theLifeValue << std::endl;
    std::cout << "noshowpos: " << std::noshowpos << theLifeValue << std::endl;
}

std::uppercase

Извежда ASCII буквите като главни при извеждане на числа. Не работи за текст:

#include <iostream>
#include <iomanip>

int main() {
    std::cout << std::uppercase;
    std::cout << std::hex << 255 << '\n';
    std::cout << std::hex << 3'600 << '\n';
}

Изход:

FF
E10

std::scientific

Това е научна нотация представяща числата: float и double.

double x = 1234.5;
std::cout << std::scientific << std::uppercase << x << std::endl;
std::cout << std::scientific << std::nouppercase << x << std::endl;

Ред 2: Представя експонентата с главна буква.
Ред 3: Представя експонентата с малка буква.

std::setprecision(n)

Този манипулатор извежда реалните числа с точност до N след десетичната запетая.

#include <iostream>
#include <iomanip>

int main() {
    const double PI = 3.14159265358979323846;
    std::cout << std::setprecision(7) << PI << std::endl;
}

std::setw(n)

Задава ширината на полето в която ще се изведе следващата стойност.

std::setfill

Задава символ за запълване на празното пространство. Пример:

std::cout << std::setfill('*');
std::cout << std::setw(10) << 42;

Изход:

********42

std::boolalpha

Извежда true, когато булев операция върне 1. Или false, когато се върне 0.

std::skipws

Пропуска бялото пространство: интервали, табулатори… нов ред…
По подразбиране входните потоци пропускат whitespace.

int x;
std::cin >> x;

Ако не трябва да се пропуска:

char c;
std::cin >> std::noskipws >> c;

Тук сме посочили основните манипулатор. Пълна информация има на този страница.