Spec-Zone.ru › C++

std::num_put<CharT,OutputIt>::put, std::num_put<CharT,OutputIt>::do_put

Определено в заголовке <locale>
(1)
public:
iter_type put( iter_type out, std::ios_base& str,
               char_type fill, bool val ) const;
iter_type put( iter_type out, std::ios_base& str,
               char_type fill, long val ) const;
iter_type put( iter_type out, std::ios_base& str,
               char_type fill, long long val ) const;
(с C++11)
iter_type put( iter_type out, std::ios_base& str,
               char_type fill, unsigned long val ) const;
iter_type put( iter_type out, std::ios_base& str,
               char_type fill, unsigned long long val ) const;
(с C++11)
iter_type put( iter_type out, std::ios_base& str,
               char_type fill, double val ) const;
iter_type put( iter_type out, std::ios_base& str,
               char_type fill, long double val ) const;
iter_type put( iter_type out, std::ios_base& str,
               char_type fill, const void* val ) const;
(2)
protected:
virtual iter_type do_put( iter_type out, std::ios_base& str,
                          char_type fill, bool val ) const;
virtual iter_type do_put( iter_type out, std::ios_base& str,
                          char_type fill, long val ) const;
virtual iter_type do_put( iter_type out, std::ios_base& str,
                          char_type fill, long long val ) const;
(с C++11)
virtual iter_type do_put( iter_type out, std::ios_base& str,
                          char_type fill, unsigned long val ) const;
virtual iter_type do_put( iter_type out, std::ios_base& str,
                          char_type fill, unsigned long long val ) const;
(с C++11)
virtual iter_type do_put( iter_type out, std::ios_base& str,
                          char_type fill, double val ) const;
virtual iter_type do_put( iter_type out, std::ios_base& str,
                          char_type fill, long double val ) const;
virtual iter_type do_put( iter_type out, std::ios_base& str,
                          char_type fill, const void* val ) const;
1) Общедоступный член-функция, вызывает защищенную виртуальную член-функцию do_put самого производного класса.
2) Записывает символы в выходную последовательность 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 и unsigned long, ll для long long и unsigned long long(с C++11).
  • Если тип val является типом с плавающей точкой, выбирается первый применимый вариант из следующего:
    • Если floatfield == std::ios_base::fixed, используется спецификатор преобразования %f
    • Если 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 равен long double, модификатор длины 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) не считается символом выравнивания.

При форматировании значения с плавающей точкой в виде шестнадцатеричной плавающей точки (т.е., когда 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, base const& 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 также добавлять для чисел с плавающей точкой

См. также

operator<<
вставляет отформатированные данные
(публичный член-функция std::basic_ostream<CharT,Traits>)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/locale/num_put/put

Spec-Zone.ru

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