std::formatter
| Определено в заголовочном файле <format>
|
||
template< class T, class CharT = char > struct formatter; |
(начиная с C++20) | |
Доступные специализации std::formatter определяют правила форматирования для данного типа. Доступные специализации соответствуют требованиям BasicFormatter и, если не указано иное, также соответствуют требованиям Formatter.
Для всех типов T и CharT, для которых не доступна специализация std::formatter<T, CharT>, эта специализация является полным типом и не доступна.
Недоступные специализации не соответствуют требованиям Formatter, и все следующие значения являются false:
- std::is_default_constructible_v
- std::is_copy_constructible_v
- std::is_move_constructible_v
- std::is_copy_assignable_v
- std::is_move_assignable_v.
Базовые стандартные специализации
В следующем списке CharT это либо char, либо wchar_t, ArithmeticT это любой cv-неквалифицированный арифметический тип, кроме char, wchar_t, char8_t, char16_t или char32_t:
| Форматтеры символов |
||
template<> struct formatter<char, char>; |
(1) | |
template<> struct formatter<char, wchar_t>; |
(2) | |
template<> struct formatter<wchar_t, wchar_t>; |
(3) | |
| Форматтеры строк |
||
template<> struct formatter<CharT*, CharT>; |
(4) | |
template<> struct formatter<const CharT*, CharT>; |
(5) | |
template< std::size_t N > struct formatter<CharT[N], CharT>; |
(6) | |
template< std::size_t N > struct formatter<const CharT[N], CharT>; |
(7) | (до C++23) |
template< class Traits, class Alloc > struct formatter<std::basic_string<CharT, Traits, Alloc>, CharT>; |
(8) | |
template< class Traits > struct formatter<std::basic_string_view<CharT, Traits>, CharT>; |
(9) | |
| Арифметические форматтеры |
||
template<> struct formatter<ArithmeticT, CharT>; |
(10) | |
| Форматтеры указателей |
||
template<> struct formatter<std::nullptr_t, CharT>; |
(11) | |
template<> struct formatter<void*, CharT>; |
(12) | |
template<> struct formatter<const void*, CharT>; |
(13) | |
Форматтеры для других указателей и указателей на элементы не доступны.
Специализации, такие как std::formatter<wchar_t, char> и std::formatter<const char*, wchar_t>, которые требуют преобразования кодировки, не доступны.
|
Каждая специализация форматтера для строкового или символьного типа дополнительно предоставляет открытую нестатическую функцию-элемент |
(начиная с C++23) |
Спецификация стандартного формата
Для базовых типов и строковых типов спецификация формата основана на спецификации формата в Python.
Синтаксис спецификаций формата:
заполнение-и-выравнивание (необязательно) знак (необязательно) #(необязательно) 0(необязательно) ширина (необязательно) точность (необязательно) L(необязательно) тип (необязательно)
|
|||||||||
Параметры знак, # и 0 допустимы только при использовании целочисленного типа представления или типа представления с плавающей запятой.
В большинстве случаев синтаксис аналогичен старому форматированию % с добавлением {} и :, используемых вместо %. Например, '%03.2f' можно преобразовать в '{:03.2f}'.
Заполнение и выравнивание
Заполнение-и-выравнивание необязательный символ заполнения (который может быть любым символом, кроме { или }), за которым следует одна из опций выравнивания <, >, ^.
Если символ заполнения не указан, по умолчанию используется символ пробела. Для спецификации формата в кодировке Юникода символ заполнения должен соответствовать одному скалярному значению Юникода.
Смысл опций выравнивания следующий:
<: Принудительно выравнивает форматированный аргумент по началу доступного пространства вставкой n символов заполнения после форматированного аргумента. Это значение по умолчанию, когда используется нецелочисленный тип представления без плавающей запятой.>: Принудительно выравнивает форматированный аргумент по концу доступного пространства вставкой n символов-заполнителей перед форматированным аргументом. Это значение по умолчанию, когда используется целочисленный тип представления или тип представления с плавающей запятой.^: Принудительно центрирует форматированный аргумент в пределах доступного пространства, вставляя символы ⌊
⌋ перед и ⌈n 2
⌉ символы после форматированного аргумента.n 2
В каждом случае n это разница минимальной ширины поля (заданной шириной) и предполагаемой ширины форматированного аргумента или 0, если разница меньше 0.
char c = 120;
auto s0 = std::format("{:6}", 42); // значение s0 равно " 42"
auto s1 = std::format("{:6}", 'x'); // значение s1 равно "x "
auto s2 = std::format("{:*<6}", 'x'); // значение s2 равно "x*****"
auto s3 = std::format("{:*>6}", 'x'); // значение s3 равно "*****x"
auto s4 = std::format("{:*^6}", 'x'); // значение s4 равно "**x***"
auto s5 = std::format("{:6d}", c); // значение s5 равно " 120"
auto s6 = std::format("{:6}", true); // значение s6 равно "true "
Знак, # и 0
Параметр знак может быть одним из следующих:
+: Указывает, что знак следует использовать как для неотрицательных, так и для отрицательных чисел. Знак+вставляется перед выходным значением для неотрицательных чисел.-: Указывает, что знак следует использовать только для отрицательных чисел (это поведение по умолчанию).- пробел: Указывает, что для неотрицательных чисел следует использовать начальный пробел, а для отрицательных чисел следует использовать знак минус.
Отрицательный ноль рассматривается как отрицательное число.
Параметр знак применяется к бесконечности с плавающей запятой и NaN.
double inf = std::numeric_limits<double>::infinity();
double nan = std::numeric_limits<double>::quiet_NaN();
auto s0 = std::format("{0:},{0:+},{0:-},{0: }", 1); // значение s0 равно "1,+1,1, 1"
auto s1 = std::format("{0:},{0:+},{0:-},{0: }", -1); // значение s1 равно "-1,-1,-1,-1"
auto s2 = std::format("{0:},{0:+},{0:-},{0: }", inf); // значение s2 равно "inf,+inf,inf, inf"
auto s3 = std::format("{0:},{0:+},{0:-},{0: }", nan); // значение s3 равно "nan,+nan,nan, nan"
Опция # приводит к использованию альтернативной формы для преобразования.
- Для целочисленных типов, когда используется двоичный, восьмеричный или шестнадцатеричный тип представления, альтернативная форма вставляет префикс (
0b,0или0x) в выходное значение после знака (возможно, пробела), если он есть, или иначе добавляет его перед выходным значением. - Для типов с плавающей запятой альтернативная форма приводит к тому, что результат преобразования конечных значений всегда содержит символ десятичной точки, даже если за ним не следуют никакие цифры. Обычно символ десятичной точки появляется в результате этих преобразований только в том случае, если за ним следует цифра. Кроме того, для преобразований
gиGконечные нули не удаляются из результата.
Опция 0 дополняет поле ведущими нулями (после любого указания знака или основания) до ширины поля, за исключением случаев, когда она применяется к бесконечности или NaN. Если присутствуют и символ 0, и опция выравнивание, символ 0 игнорируется.
char c = 120;
auto s1 = std::format("{:+06d}", c); // значение s1 равно "+00120"
auto s2 = std::format("{:#06x}", 0xa); // значение s2 равно "0x000a"
auto s3 = std::format("{:<06}", -42); // значение s3 равно "-42 "
// (0 игнорируется, потому что выравнивание <)
Ширина и точность
Ширина это либо положительное десятичное число, либо вложенное поле замены ({} или {n}). Если она присутствует, то определяет минимальную ширину поля.
точность представляет собой точку (.), за которой следует либо неотрицательное десятичное число, либо вложенное поле замены. В этом поле указывается точность или максимальный размер поля. Её можно использовать только с типами с плавающей запятой и строками.
- Для типов с плавающей запятой это поле определяет точность форматирования.
- Для строковых типов оно обеспечивает верхнюю границу предполагаемой ширины (смотрите ниже) префикса строки, которая будет скопирована в выходные данные. Для строки в кодировке Юникода текст, который нужно скопировать в вывод, представляет собой самый длинный префикс из целых расширенных grapheme кластеров, чья предполагаемая ширина не превышает точности.
Если вложенное поле замены используется для ширины или точности, а соответствующий аргумент не имеет целочисленного типа (до C++23)стандартного целочисленного типа со знаком или без знака (начиная с C++23), или имеет отрицательное значение, генерируется исключение типа std::format_error.
float pi = 3.14f;
auto s1 = std::format("{:10f}", pi); // s1 = " 3.140000" (ширина = 10)
auto s2 = std::format("{:{}f}", pi, 10); // s2 = " 3.140000" (ширина = 10)
auto s3 = std::format("{:.5f}", pi); // s3 = "3.14000" (точность = 5)
auto s4 = std::format("{:.{}f}", pi, 5); // s4 = "3.14000" (точность = 5)
auto s5 = std::format("{:10.5f}", pi); // s5 = " 3.14000"
// (ширина = 10, точность = 5)
auto s6 = std::format("{:{}.{}f}", pi, 10, 5); // s6 = " 3.14000"
// (ширина = 10, точность = 5)
// генерирует исключение: ширина не целочисленного типа
auto b1 = std::format("{:{}f}", pi, 10.0);
// генерирует исключение: ширина отрицательна
auto b2 = std::format("{:{}f}", pi, -10);
// генерирует исключение: точность не целочисленного типа
auto b3 = std::format("{:.{}f}", pi, 5.0);
Ширина строки определяется как предполагаемое количество позиций столбцов, подходящих для её отображения в терминале.
Для расчёта ширины предполагается, что строка находится в кодировке, определяемой реализацией. Метод вычисления ширины не указан, но для строки в кодировке Юникод реализация должна оценивать ширину строки как сумму предполагаемых ширин первых кодовых точек в её расширенных grapheme кластерах. Предполагаемая ширина равна 2 для следующих кодовых точек и равна 1 иначе:
- Любая кодовая точка, свойство Юникода
East_Asian_Width, которое имеет значение Fullwidth (F) или Wide (W) - U+4DC0 - U+4DFF (Yijing Символы Гексаграммы)
- U+1F300 – U+1F5FF (Разные Символы и Пиктограммы)
- U+1F900 – U+1F9FF (Дополнительные Символы и Пиктограммы)
auto s1 = std::format("{:.^5s}", "🐱"); // s1 = ".🐱.."
auto s2 = std::format("{:.5s}", "🐱🐱🐱"); // s2 = "🐱🐱"
auto s3 = std::format("{:.<5.5s}", "🐱🐱🐱"); // s3 = "🐱🐱."
L (форматирование, зависящее от локали)
Параметр L приводит к использованию формы, зависящей от локали. Эта опция действительна только для арифметических типов.
- Для целочисленных типов, специфичная для локали форма вставляет соответствующие символы-разделители групп цифр в соответствии с локалью контекста.
- Для типов с плавающей запятой, специфичная для локали форма вставляет соответствующую группу цифр и символы-разделители системы счисления в соответствии с локалью контекста.
- Для текстового представления
boolв форме, зависящей от локали, используется соответствующая строка, как если бы она была получена с помощью std::numpunct::truename или std::numpunct::falsename.
Тип
Параметр тип определяет, как должны быть представлены данные.
Доступные типы строкового представления:
- нет,
s: Копирует строку в выходной файл.
|
(начиная с C++23) |
Доступные целочисленные типы представления для целочисленных типов, отличных от char, wchar_t и bool:
b: Двоичный формат. Производит вывод, как если бы вызовstd::to_chars(первый, последний, значение, 2). Префикс базы0b.B: То же, чтоb, за исключением того, что префикс базы0B.c: Копирует символstatic_cast<CharT>(значение)в вывод, гдеCharTэто тип символа строки формата. Генерирует std::format_error, если значение не находится в диапазоне представимых значений дляCharT.d: Десятичный формат. Производит вывод, как если бы вызовstd::to_chars(первый, последний, значение).o: Восьмеричный формат. Производит вывод, как если бы вызовstd::to_chars(первый, последний, значение, 8). Префикс базы равен0, если соответствующее значение аргумента не равно нулю, и пусто иначе.x: Шестнадцатеричный формат. Производит вывод, как если бы вызовstd::to_chars(первый, последний, значение, 16). Префикс базы равен0x.X: То же, чтоx, за исключением того, что для цифр выше 9 используются прописные буквы, а префикс базы равен0X.- нет: То же, что
d.
Доступные типы представления char и wchar_t:
- нет,
c: Копирует символ в вывод. b,B,d,o,x,X: Использует целочисленные типы представления.
|
(начиная с C++23) |
Доступные типы представления bool:
- нет,
s: Копирует текстовое представление (trueилиfalseили в форме, зависящей от локали) в вывод. b,B,d,o,x,X: Использует целочисленные типы представления со значениемstatic_cast<unsigned char>(значение).
Доступные типы представления с плавающей запятой:
a: Если указана точность, выходные данные производятся так, как вызовstd::to_chars(первый, последний, значение, std::chars_format::hex, точность), гдеточностьэто указанная точность; иначе вывод производится так, как вызовstd::to_chars(первый, последний, значение, std::chars_format::hex).A: То же, что иa, за исключением того, что для цифр выше 9 используются прописные буквы, а для обозначения показателя степени используетсяP.e: Создаёт вывод, как вызовstd::to_chars(первый, последний, значение, std::chars_format::scientific, точность), гдеточностьэто указанная точность, или 6, если точность не указана.E: То же, что иe, за исключением того, что он используетEдля указания показателя степени.f,F: Создаёт вывод, как вызовstd::to_chars(первый, последний, значение, std::chars_format::fixed, точность), гдеточностьэто указанная точность, или 6, если точность не указана.g: Создаёт вывод, как вызовstd::to_chars(первый, последний, значение, std::chars_format::general, точность), гдеточностьэто указанная точность, или 6, если точность не указана.G: То же, чтоg, за исключением того, что он используетEдля указания показателя степени.- нет: Если указана точность, вывод создаётся так, как вызов
std::to_chars(первый, последний, значение, std::chars_format::general, точность), гдеточностьэто указанная точность; иначе вывод производится так, как вызовstd::to_chars(первый, последний, значение).
Для типов представления в нижнем регистре бесконечность и NaN форматируются как inf и nan соответственно.
Для типов представления в верхнем регистре бесконечность и NaN форматируются как INF и NAN соответственно.
Доступные типы представления указателей (также используемые для std::nullptr_t):
- нет,
p: Если std::uintptr_t определён, вывод создаётся так, как вызовstd::to_chars(first, last, reinterpret_cast<std::uintptr_t>(значение), 16)с добавлением префикса0xк выводу; иначе вывод определяется реализацией.
|
(начиная с C++26) |
Форматирование экранированных символов и строк (начиная с C++23)
Символ или строку можно отформатировать экранированными, чтобы сделать их более подходящими для отладки или журналирования.
Экранирование осуществляется следующим образом:
- Для каждой правильно сформированной последовательности кодовой единицы, кодирующей символ C:
- Если C является одним из символов в следующей таблице, используется соответствующая управляющая последовательность.
| Символ | Управляющая последовательность | Примечание |
|---|---|---|
| горизонтальная табуляция (байт 0x09 в кодировке ASCII) | \t |
|
| перевод строки – новая строка (байт 0x0a в кодировке ASCII) | \n |
|
| возврат каретки (байт 0x0d в кодировке ASCII) | \r |
|
| двойная кавычка (байт 0x22 в кодировке ASCII) | \" |
Используется только в том случае, если вывод представляет собой строку в двойных кавычках |
| одинарная кавычка (байт 0x27 в кодировке ASCII) | \' |
Используется только в том случае, если вывод представляет собой строку в одинарных кавычках |
| обратная косая черта (байт 0x5c в кодировке ASCII) | \\ |
- Иначе, если C не является символом пробела (байт 0x20 в кодировке ASCII), и либо
- соответствующая кодировка символов является кодировкой Юникода и
- C соответствует скалярному значению Юникода, свойство Юникода
General_Categoryкоторого имеет значение в группахSeparator(Z) илиOther(C), или - C непосредственно не предшествует неэкранированный символ, а C соответствует скалярному значению Юникода, имеющему свойство Юникода
Grapheme_Extend=Yes, или
- C соответствует скалярному значению Юникода, свойство Юникода
- соответствующая кодировка символов не является кодировкой Юникода, а C является одним из определяемого реализацией набора разделителей или непечатаемых символов
- управляющая последовательность равна
\u{последовательность-шестнадцатеричных-цифр}, гдепоследовательность-шестнадцатеричных-цифрэто кратчайшее шестнадцатеричное представление буквы C с использованием шестнадцатеричных цифр в нижнем регистре.
- Иначе C копируется как есть.
- Последовательность кодовых единиц, представляющая собой последовательность сдвига, оказывает неопределённое влияние на вывод и дальнейшее декодирование строки.
- Каждая из других кодовых единиц (то есть тех, которые находятся в неправильно сформированных последовательностях кодовых единиц) заменяется на
\x{последовательность-шестнадцатеричных-цифр}, гдепоследовательность-шестнадцатеричных-цифрэто кратчайшее шестнадцатеричное представление кодовой единицы с использованием шестнадцатеричных цифр в нижнем регистре.
Экранированное строковое представление строки создаётся экранированием последовательностей кодовых единиц в строке, как описано выше, и заключением результата в двойные кавычки.
Экранированное представление символа создаётся его экранированием, как описано выше, и заключением результата в одинарные кавычки.
auto s1 = std::format("[{:?}]", "h\tllo"); // s1 имеет значение: ["h\tllo"]
auto s2 = std::format("[{:?}]", "Спасибо, Виктор ♥!"); // s2 имеет значение:
// ["Спасибо, Виктор ♥!"]
auto s3 = std::format("[{:?}] [{:?}]", '\'', '"'); // s3 имеет значение: ['\'', '"']
// Следующие примеры предполагают использование кодировки UTF-8.
auto s4 = std::format("[{:?}]", std::string("\0 \n \t \x02 \x1b", 9));
// s4 имеет значение:
// [\u{0} \n \t \u{2} \u{1b}]
auto s5 = std::format("[{:?}]", "\xc3\x28"); // неверный UTF-8
// s5 имеет значение: ["\x{c3}("]
auto s6 = std::format("[{:?}]", "\u0301"); // s6 имеет значение: ["\u{301}"]
auto s7 = std::format("[{:?}]", "\\\u0301"); // s7 имеет значение: ["\\\u{301}"]
auto s8 = std::format("[{:?}]", "e\u0301\u0323"); // s8 имеет значение: ["ẹ́"]
Стандартные специализации для библиотечных типов
поддержка форматирования для duration (специализация шаблона класса) | |
поддержка форматирования для sys_time (специализация шаблона класса) | |
поддержка форматирования для utc_time (специализация шаблона класса) | |
поддержка форматирования для tai_time (специализация шаблона класса) | |
поддержка форматирования для gps_time (специализация шаблона класса) | |
поддержка форматирования для file_time (специализация шаблона класса) | |
поддержка форматирования для local_time (специализация шаблона класса) | |
поддержка форматирования для day (специализация шаблона класса) | |
поддержка форматирования для month (специализация шаблона класса) | |
поддержка форматирования для year (специализация шаблона класса) | |
поддержка форматирования для weekday (специализация шаблона класса) | |
поддержка форматирования для weekday_indexed (специализация шаблона класса) | |
поддержка форматирования для weekday_last (специализация шаблона класса) | |
поддержка форматирования для month_day (специализация шаблона класса) | |
поддержка форматирования для month_day_last (специализация шаблона класса) | |
поддержка форматирования для month_weekday (специализация шаблона класса) | |
поддержка форматирования для month_weekday_last (специализация шаблона класса) | |
поддержка форматирования для year_month (специализация шаблона класса) | |
поддержка форматирования для year_month_day (специализация шаблона класса) | |
поддержка форматирования для year_month_day_last (специализация шаблона класса) | |
поддержка форматирования для year_month_weekday (специализация шаблона класса) | |
поддержка форматирования для year_month_weekday_last (специализация шаблона класса) | |
поддержка форматирования для hh_mm_ss (специализация шаблона класса) | |
поддержка форматирования для sys_info (специализация шаблона класса) | |
поддержка форматирования для local_info (специализация шаблона класса) | |
поддержка форматирования для zoned_time (специализация шаблона класса) | |
поддержка форматирования для basic_stacktrace (специализация шаблона класса) | |
поддержка форматирования для stacktrace_entry (специализация шаблона класса) | |
поддержка форматирования для thread::id (специализация шаблона класса) |
Пример
#include <format>
#include <iostream>
// Обёртка для типа Т
template<class T>
struct Box
{
T value;
};
// Оболочку Box<T> можно отформатировать с использованием
// спецификации формата обёрнутого значения
template<class T, class CharT>
struct std::formatter<Box<T>, CharT> : std::formatter<T, CharT>
{
// parse() унаследована от базового класса
// Определяем format(), вызвав реализацию базового класса с обёрнутым значением
template<class FormatContext>
auto format(Box<T> t, FormatContext& fc) const
{
return std::formatter<T, CharT>::format(t.value, fc);
}
};
int main()
{
Box<int> v = {42};
std::cout << std::format("{:#x}", v);
}
Вывод:
0x2a
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 3721 | C++20 | ноль не допускается для поля ширины в стандартной спецификации формата | допускается ноль, если он указан через поле замены |
Смотрите также
(C++20)(C++20)(C++20) |
состояние форматирования, включая все аргументы форматирования и итератор вывода (шаблон класса) |
(C++23) |
указывает, что тип является форматируемым, то есть он специализирует std::formatter и предоставляет функции-элементы parse и format (концепт) |