Spec-Zone.ru › C++

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)
1-8) Открытая функция-член вызывает защищённую виртуальную функцию-член do_put наиболее производного класса.
9-16) Записывает символы в выходную последовательность 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 является типом с плавающей точкой, выбирается первый подходящий вариант из следующих:
  • Если floatfield == std::ios_base::fixed, используется спецификатор преобразования %f.
(до C++11)
  • Если floatfield == std::ios_base::fixed && !uppercase, используется спецификатор преобразования %f.
  • Если floatfield == std::ios_base::fixed, используется спецификатор преобразования %F.
(начиная с C++11)
  • Если floatfield == std::ios_base::scientific && !uppercase, используется спецификатор преобразования %e.
  • Если floatfield == std::ios_base::scientific, используется спецификатор преобразования %E.
  • Если floatfield == (std::ios_base::fixed | std::ios_base::scientific) && !uppercase, используется спецификатор преобразования %a.
  • Если floatfield == (std::ios_base::fixed | std::ios_base::scientific), используется спецификатор преобразования %A.
(начиная с 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 (то есть когда floatfield == (std::ios_base::fixed | std::ios_base::scientific)) точность потока не используется; вместо этого число всегда выводится с точностью, достаточной для точного представления значения.

(начиная с 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" нельзя было вывести их можно вывести

См. также

operator<<
вставляет форматированные данные
(открытая функция-член класса 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API