std::num_put<CharT,OutputIt>::put, std::num_put<CharT,OutputIt>::do_put
Определён в заголовочном файле <locale> | ||
|---|---|---|
public:
iter_type put( iter_type out, std::ios_base& str,
char_type fill, bool val ) const;
| (1) | |
iter_type put( iter_type out, std::ios_base& str,
char_type fill, long val ) const;
| (2) | |
iter_type put( iter_type out, std::ios_base& str,
char_type fill, long long val ) const;
| (3) | (начиная с C++11) |
iter_type put( iter_type out, std::ios_base& str,
char_type fill, unsigned long val ) const;
| (4) | |
iter_type put( iter_type out, std::ios_base& str,
char_type fill, unsigned long long val ) const;
| (5) | (начиная с C++11) |
iter_type put( iter_type out, std::ios_base& str,
char_type fill, double val ) const;
| (6) | |
iter_type put( iter_type out, std::ios_base& str,
char_type fill, long double val ) const;
| (7) | |
iter_type put( iter_type out, std::ios_base& str,
char_type fill, const void* val ) const;
| (8) | |
protected:
virtual iter_type do_put( iter_type out, std::ios_base& str,
char_type fill, bool val ) const;
| (9) | |
virtual iter_type do_put( iter_type out, std::ios_base& str,
char_type fill, long val ) const;
| (10) | |
virtual iter_type do_put( iter_type out, std::ios_base& str,
char_type fill, long long val ) const;
| (11) | (начиная с C++11) |
virtual iter_type do_put( iter_type out, std::ios_base& str,
char_type fill, unsigned long val ) const;
| (12) | |
virtual iter_type do_put( iter_type out, std::ios_base& str,
char_type fill, unsigned long long val ) const;
| (13) | (начиная с C++11) |
virtual iter_type do_put( iter_type out, std::ios_base& str,
char_type fill, double val ) const;
| (14) | |
virtual iter_type do_put( iter_type out, std::ios_base& str,
char_type fill, long double val ) const;
| (15) | |
virtual iter_type do_put( iter_type out, std::ios_base& str,
char_type fill, const void* val ) const;
| (16) |
do_put наиболее производного класса.out, представляющие значение val, отформатированное в соответствии с флагами форматирования str.flags() и аспектами локали std::numpunct и std::ctype, заданной в потоке str. Эта функция вызывается всеми операторами форматированного вывода потока, например std::cout << n;.Преобразование выполняется в четыре этапа:
Этап 1: выбор спецификатора преобразования
- Флаги формата ввода-вывода извлекаются так, как если бы это выполнялось следующим образом:
fmtflags basefield = (str.flags() & std::ios_base::basefield);fmtflags uppercase = (str.flags() & std::ios_base::uppercase);fmtflags floatfield = (str.flags() & std::ios_base::floatfield);fmtflags showpos = (str.flags() & std::ios_base::showpos);fmtflags showbase = (str.flags() & std::ios_base::showbase);fmtflags showpoint = (str.flags() & std::ios_base::showpoint);
- Если тип
val— bool:- Если
boolalpha == 0, тоvalпреобразуется к типу int и выполняется целочисленный вывод. - Если
boolalpha != 0, извлекаетсяstd::use_facet<std::numpunct<CharT>>(str.getloc()).truename(), еслиval == true, илиstd::use_facet<std::numpunct<CharT>>(str.getloc()).falsename(), еслиval == false, а затем каждый очередной символcэтой строки выводится вoutс помощью*out++ = c. В этом случае дальнейшая обработка не выполняется, функция возвращаетout.
- Если
- Если тип
valявляется целочисленным типом, выбирается первый подходящий вариант из следующих:- Если
basefield == oct, используется спецификатор преобразования%o. - Если
basefield == hex && !uppercase, используется спецификатор преобразования%x. - Если
basefield == hex, используется спецификатор преобразования%X. - Если тип
valзнаковый, используется спецификатор преобразования%d. - Если тип
valбеззнаковый, используется спецификатор преобразования%u.
- Если
- Для целочисленных типов при необходимости к спецификации преобразования добавляется модификатор длины:
lдля long и unsignedlong,llдля longlong и unsignedlonglong(начиная с C++11). - Если тип
valявляется типом с плавающей точкой, выбирается первый подходящий вариант из следующих:
| (до C++11) |
| (начиная с C++11) |
- Если
floatfield == std::ios_base::scientific && !uppercase, используется спецификатор преобразования%e. - Если
floatfield == std::ios_base::scientific, используется спецификатор преобразования%E.
| (начиная с C++11) |
- Если
!uppercase, используется спецификатор преобразования%g. - В противном случае используется спецификатор преобразования
%G.
- Если
- Кроме того:
- Если тип
val— longdouble, к спецификатору преобразования добавляется модификатор длиныL. - Если тип
valявляется типом с плавающей точкой иfloatfield != (ios_base::fixed | ios_base::scientific)(начиная с C++11), добавляется модификатор точности со значениемstr.precision(). В противном случае точность не задаётся.
- Если тип
- Для целочисленных типов и типов с плавающей точкой, если установлен
showpos, в начало добавляется модификатор+. - Для целочисленных типов, если установлен
showbase, в начало добавляется модификатор#. - Для типов с плавающей точкой, если установлен
showpoint, в начало добавляется модификатор#. - Если тип
val— void*, используется спецификатор преобразования%p - Создаётся строка узких символов, как если бы был вызван
std::printf(spec, val)в локали "C", гдеspec— выбранный спецификатор преобразования.
Этап 2: преобразование с учётом локали
- Каждый символ
c, полученный на этапе 1, кроме десятичного разделителя'.', преобразуется вCharTвызовомstd::use_facet<std::ctype<CharT>>(str.getloc()).widen(c). - Для арифметических типов в последовательность вставляется символ-разделитель тысяч, полученный из
std::use_facet<std::numpunct<CharT>>(str.getloc()).thousands_sep(), в соответствии с правилами группировки, заданнымиstd::use_facet<std::numpunct<CharT>>(str.getloc()).grouping(). - Символы десятичного разделителя (
'.') заменяются наstd::use_facet<std::numpunct<CharT>>(str.getloc()).decimal_point().
Этап 3: дополнение
- Флаг выравнивания извлекается так, как если бы это выполнялось с помощью
std::fmtflags adjustfield = (flags & (std::ios_base::adjustfield)), и проверяется для определения положения символов дополнения следующим образом:- Если
adjustfield == std::ios_base::left, символы дополнения добавляются после. - Если
adjustfield == std::ios_base::right, символы дополнения добавляются перед. - Если
adjustfield == std::ios_base::internalи в представлении присутствует знак, символы дополнения добавляются после знака. - Если
adjustfield == std::ios_base::internalи представление этапа 1 начинается с 0x или 0X, символы дополнения добавляются после x или X. - В противном случае символы дополнения добавляются перед.
- Если
- Если
str.width()не равен нулю (например, только что был использованstd::setw) и количество символовCharTпосле этапа 2 меньшеstr.width(), копии символаfillвставляются в указанное положение, чтобы увеличить длину последовательности доstr.width().
В любом случае вызывается str.width(0), чтобы отменить действие std::setw.
Этап 4: вывод
Каждый очередной символ c из последовательности символов CharT, полученной на этапе 3, выводится так, как если бы был вызван *out++ = c.
Параметры
| out | - | итератор, указывающий на первый символ, который будет перезаписан |
| str | - | поток, из которого извлекаются сведения о форматировании |
| fill | - | символ заполнения, используемый, если результат требуется дополнить до ширины поля |
| val | - | значение, которое преобразуется в строку и выводится |
Возвращаемое значение
out
Примечания
Начальный ноль, создаваемый спецификатором преобразования #o (например, в результате сочетания std::showbase и std::oct), не считается символом заполнения.
| При форматировании значения с плавающей точкой в формате hexfloat (то есть когда | (начиная с C++11) |
Пример
Вывод числа непосредственно с помощью аспекта и демонстрация пользовательского аспекта:
#include <iostream>
#include <locale>
// this custom num_put outputs squares of all integers (except long long)
struct squaring_num_put : std::num_put<char>
{
iter_type do_put(iter_type out, std::ios_base& str,
char_type fill, long val) const
{
return std::num_put<char>::do_put(out, str, fill, val * val);
}
iter_type do_put(iter_type out, std::ios_base& str,
char_type fill, unsigned long val) const
{
return std::num_put<char>::do_put(out, str, fill, val * val);
}
};
int main()
{
auto& facet = std::use_facet<std::num_put<char>>(std::locale());
facet.put(std::cout, std::cout, '0', 2.71);
std::cout << '\n';
std::cout.imbue(std::locale(std::cout.getloc(), new squaring_num_put));
std::cout << 6 << ' ' << -12 << '\n';
} Вывод:
2.71 36 144
Реализация operator<< для пользовательского типа.
#include <iostream>
#include <iterator>
#include <locale>
struct base { long x = 10; };
template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const base& b)
{
try
{
typename std::basic_ostream<CharT, Traits>::sentry s(os);
if (s)
{
std::ostreambuf_iterator<CharT, Traits> it(os);
std::use_facet<std::num_put<CharT>>(os.getloc())
.put(it, os, os.fill(), b.x);
}
}
catch (...)
{
// set badbit on os and rethrow if required
}
return os;
}
int main()
{
base b;
std::cout << b;
} Вывод:
10
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применялся к | Опубликованное поведение | Корректное поведение |
|---|---|---|---|
| LWG 34 | C++98 | перегрузка для bool использовала несуществующие членыtruename и falsename класса std::ctype | используются эти члены класса std::numpunct |
| LWG 231 | C++98 | модификатор точности добавлялся только при(flags & fixed) != 0 или str.precision() > 0 | эти условия удалены |
| LWG 282 | C++98 | разделители тысяч вставлялись на этапе 2 только для целочисленных типов | также вставляются для типов с плавающей точкой |
| LWG 4084 | C++11 |
"NAN" и "INF" нельзя было вывести | их можно вывести |
См. также
| вставляет форматированные данные (открытая функция-член класса std::basic_ostream<CharT,Traits>) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/locale/num_put/put