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 — это любой неквалифицированный арифметический тип, кроме 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}'.
Заполнение и выравнивание
заполнение и выравнивание — это необязательный символ заполнения (который может быть любым символом, кроме { или }), за которым следует один из параметров выравнивания <, >, ^.
Если символ заполнения не указан, он по умолчанию равен пробелу. Для спецификации форматирования в кодировке Unicode символ заполнения должен соответствовать одному значению скаляра Unicode.
Значение параметров выравнивания:
-
<: Принудительно выравнивает форматируемое значение к началу доступного пространства, вставляя n символов заполнения после форматируемого значения. Это значение по умолчанию для использования нецелочисленного и неплавающего типа представления. -
>: Принудительно выравнивает форматируемое значение к концу доступного пространства, вставляя n символов заполнения перед форматируемым значением. Это значение по умолчанию для использования целочисленного или плавающего типа представления. -
^: Принудительно центрирует форматируемое значение в доступном пространстве, вставляя ⌊n/2⌋ символов перед и ⌈n/2⌉ символов после форматируемого значения.
В каждом случае n — это разность минимальной ширины поля (указанной в ширина) и оцененной ширины форматируемого значения, или 0, если эта разность меньше 0.
char c = 120;
auto s0 = std::format("{:6}", 42); // value of s0 is " 42"
auto s1 = std::format("{:6}", 'x'); // value of s1 is "x "
auto s2 = std::format("{:*<6}", 'x'); // value of s2 is "x*****"
auto s3 = std::format("{:*>6}", 'x'); // value of s3 is "*****x"
auto s4 = std::format("{:*^6}", 'x'); // value of s4 is "**x***"
auto s5 = std::format("{:6d}", c); // value of s5 is " 120"
auto s6 = std::format("{:6}", true); // value of s6 is "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); // value of s0 is "1,+1,1, 1"
auto s1 = std::format("{0:},{0:+},{0:-},{0: }", -1); // value of s1 is "-1,-1,-1,-1"
auto s2 = std::format("{0:},{0:+},{0:-},{0: }", inf); // value of s2 is "inf,+inf,inf, inf"
auto s3 = std::format("{0:},{0:+},{0:-},{0: }", nan); // value of s3 is "nan,+nan,nan, nan"Параметр # вызывает использование альтернативной формы для преобразования.
- Для целочисленных типов, при использовании двоичного, восьмеричного или шестнадцатеричного типа представления, альтернативная форма вставляет префикс (
0b,0, или0x) в выводимое значение после символа знака (возможно, пробела), если он есть, или добавляет его перед выводимым значением в противном случае. - Для типов с плавающей точкой альтернативная форма заставляет результат преобразования конечных значений всегда содержать десятичную точку, даже если за ней нет цифр. Обычно десятичная точка появляется в результате этих преобразований только в том случае, если за ней следует цифра. Кроме того, для преобразований
gиGхвостовые нули не удаляются из результата.
Параметр 0 заполняет поле ведущими нулями (после любого указания знака или основания) до ширины поля, за исключением случаев, когда он применяется к бесконечности или NaN. Если символ 0 и параметр выравнивания оба присутствуют, символ 0 игнорируется.
char c = 120;
auto s1 = std::format("{:+06d}", c); // value of s1 is "+00120"
auto s2 = std::format("{:#06x}", 0xa); // value of s2 is "0x000a"
auto s3 = std::format("{:<06}", -42); // value of s3 is "-42 "
// (0 is ignored because of < alignment)Ширина и точность
ширина — это либо положительное десятичное число, либо вложенное поле замены ({} или {n}). Если он присутствует, он указывает минимальную ширину поля.
точность — это точка (.) , за которой следует либо неотрицательное десятичное число, либо вложенное поле замены. Это поле указывает точность или максимальный размер поля. Он может использоваться только с типами с плавающей точкой и строками.
- Для типов с плавающей точкой это поле указывает точность форматирования.
- Для строковых типов он задаёт верхнюю границу для оценки ширины (см. ниже) префикса строки, который должен быть скопирован в выходные данные. Для строки в кодировке Unicode текст, который должен быть скопирован в выходные данные, — это самый длинный префикс целых расширенных графемных кластеров, чья оценка ширины не превышает точность.
Если вложенное поле замены используется для ширина или точность, и соответствующее значение не является целочисленного типа(до C++23)стандартным знаковым или беззнаковым целочисленным типом(с C++23), или отрицательно, выбрасывается исключение типа std::format_error.
float pi = 3.14f;
auto s1 = std::format("{:10f}", pi); // s1 = " 3.140000" (width = 10)
auto s2 = std::format("{:{}f}", pi, 10); // s2 = " 3.140000" (width = 10)
auto s3 = std::format("{:.5f}", pi); // s3 = "3.14000" (precision = 5)
auto s4 = std::format("{:.{}f}", pi, 5); // s4 = "3.14000" (precision = 5)
auto s5 = std::format("{:10.5f}", pi); // s5 = " 3.14000"
// (width = 10, precision = 5)
auto s6 = std::format("{:{}.{}f}", pi, 10, 5); // s6 = " 3.14000"
// (width = 10, precision = 5)
auto b1 = std::format("{:{}f}", pi, 10.0); // throws: width is not of integral type
auto b2 = std::format("{:{}f}", pi, -10); // throws: width is negative
auto b3 = std::format("{:.{}f}", pi, 5.0); // throws: precision is not of integral typeШирина строки определяется как приблизительное количество позиций колонок, подходящих для её отображения в терминале.
Для целей вычисления ширины строка предполагается в реализации-зависимом кодировании. Метод вычисления ширины не определен, но для строки в кодировании Unicode реализация должна оценить ширину строки как сумму оценок ширины первых кодовых точек в её расширенных кластерах графем. Оценочная ширина равна 2 для следующих кодовых точек, и равна 1 в противном случае:
- Любая кодовая точка, чьё свойство Unicode
East_Asian_Widthимеет значение «Полная ширина» (F) или «Широкая» (W) - U+4DC0 - U+4DFF (Символы гексаграмм И Цзин)
- 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.
Тип
Опция type определяет, как должны быть представлены данные.
Доступные типы представления строк:
- none,
s: Копирует строку в выходной поток.
| (с C++23) |
Доступные целочисленные типы представления для целочисленных типов, отличных от char, wchar_t и bool, являются:
-
b: Двоичный формат. Создаёт вывод так, как будто вызываетсяstd::to_chars(first, last, value, 2). Префикс основания0b. -
B: аналогичноb, за исключением того, что префикс основания0B. -
c: Копирует символstatic_cast<CharT>(value)в выходной поток, гдеCharT- тип символа строки формата. Бросает исключениеstd::format_errorесли значение не входит в диапазон представимых значений дляCharT. -
d: Десятичный формат. Создаёт вывод так, как будто вызываетсяstd::to_chars(first, last, value). -
o: Восьмеричный формат. Создаёт вывод так, как будто вызываетсяstd::to_chars(first, last, value, 8). Префикс основания0если соответствующее значение аргумента не равно нулю, и пустая строка в противном случае. -
x: Шестнадцатеричный формат. Создаёт вывод так, как будто вызываетсяstd::to_chars(first, last, value, 16). Префикс основания0x. -
X: аналогичноx, за исключением того, что использует заглавные буквы для цифр выше 9, а префикс основания0X. - none: аналогично
d.
Доступные типы представления char и wchar_t:
- none,
c: Копирует символ в выходной поток. -
b,B,d,o,x,X: Использует целочисленные типы представления со значениемstatic_cast<unsigned char>(value)илиstatic_cast<std::make_unsigned_t<wchar_t>>(value)соответственно.
| (с C++23) |
Доступные типы представления bool:
- none,
s: Копирует текстовое представление (trueилиfalse, или форма, специфичная для локали) в выходной поток. -
b,B,d,o,x,X: Использует целочисленные типы представления со значениемstatic_cast<unsigned char>(value).
Доступные типы представления с плавающей точкой:
-
a: Если указана точность, создаёт вывод так, как будто вызываетсяstd::to_chars(first, last, value, std::chars_format::hex, precision)с указанной точностью; в противном случае вывод создаётся как будто вызываетсяstd::to_chars(first, last, value, std::chars_format::hex). -
A: аналогичноa, за исключением того, что используются заглавные буквы для цифр выше 9 и используетсяPдля обозначения экспоненты. -
e: Создаёт вывод как будто вызываетсяstd::to_chars(first, last, value, std::chars_format::scientific, precision)с указанной точностью, или 6, если точность не указана. -
E: аналогичноe, за исключением того, что используетсяEдля обозначения экспоненты. -
f,F: Создаёт вывод как будто вызываетсяstd::to_chars(first, last, value, std::chars_format::fixed, precision)с указанной точностью, или 6, если точность не указана. -
g: Создаёт вывод как будто вызываетсяstd::to_chars(first, last, value, std::chars_format::general, precision)с указанной точностью, или 6, если точность не указана. -
G: аналогичноg, за исключением того, что используетсяEдля обозначения экспоненты. - none: Если указана точность, создаёт вывод как будто вызывается
std::to_chars(first, last, value, std::chars_format::general, precision)с указанной точностью; в противном случае вывод создаётся как будто вызываетсяstd::to_chars(first, last, value).
Для строчных типов представления бесконечность и NaN форматируются как inf и nan соответственно. Для прописных типов представления бесконечность и NaN форматируются как INF и NAN соответственно.
Доступные типы представления указателей (также используются для std::nullptr_t):
- none,
p: Еслиstd::uintptr_tопределено, создаёт вывод как будто вызываетсяstd::to_chars(first, last, reinterpret_cast<std::uintptr_t>(value), 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), и либо
-
- ассоциированное кодирование символов является кодированием Unicode и
- C соответствует скалярному значению Unicode, чьё свойство Unicode
General_Categoryимеет значение в группахSeparator(Z) илиOther(C), или - C не предшествует неэкранированный символ, и C соответствует скалярному значению Unicode, которое имеет свойство Unicode
Grapheme_Extend=Yes, или - ассоциированное кодирование символов не является кодированием Unicode и C является одним из определенных реализацией набора разделителей или непечатаемых символов
- последовательность экранирования равна
\u{hex-digit-sequence}, гдеhex-digit-sequence- кратчайшее шестнадцатеричное представление C с использованием строчных шестнадцатеричных цифр.
- В противном случае, C копируется как есть.
- Последовательность кодовых единиц, которая является последовательностью смены кодировки, оказывает неопределенное влияние на вывод и дальнейшее декодирование строки.
- Другие кодовые единицы (т.е. те, которые находятся в неправильных последовательностях кодовых единиц) заменяются на
\x{hex-digit-sequence}, гдеhex-digit-sequence- кратчайшее шестнадцатеричное представление кодовой единицы с использованием строчных шестнадцатеричных цифр.
Представление экранированной строки строится путем экранирования последовательностей кодовых единиц в строке, как описано выше, и заключения результата в двойные кавычки.
Экранированное представление символа строится путём его экранирования, как описано выше, и заключения результата в одинарные кавычки.
auto s1 = std::format("[{:?}]", "h\tllo"); // s1 has value: ["h\tllo"]
auto s2 = std::format("[{:?}]", "Спасибо, Виктор ♥!"); // s2 has value:
// ["Спасибо, Виктор ♥!"]
auto s3 = std::format("[{:?}] [{:?}]", '\'', '"'); // s3 has value: ['\'', '"']
// The following examples assume use of the UTF-8 encoding
auto s4 = std::format("[{:?}]", std::string("\0 \n \t \x02 \x1b", 9));
// s4 has value:
// [\u{0} \n \t \u{2} \u{1b}]
auto s5 = std::format("[{:?}]", "\xc3\x28"); // invalid UTF-8
// s5 has value: ["\x{c3}("]
auto s6 = std::format("[{:?}]", "\u0301"); // s6 has value: ["\u{301}"]
auto s7 = std::format("[{:?}]", "\\\u0301"); // s7 has value: ["\\\u{301}"]
auto s8 = std::format("[{:?}]", "e\u0301\u0323"); // s8 has value: ["ẹ́"]Стандартные специализации для типов библиотеки
|
(C++20) | Поддержка форматирования для duration (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для sys_time (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для utc_time (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для tai_time (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для gps_time (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для file_time (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для local_time (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для day (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для month (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для year (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для weekday (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для weekday_indexed (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для weekday_last (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для month_day (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для month_day_last (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для month_weekday (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для month_weekday_last (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для year_month (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для year_month_day (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для year_month_day_last (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для year_month_weekday (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для year_month_weekday_last (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для hh_mm_ss (специализация шаблонного класса) |
|
(C++20) | Поддержка форматирования для sys_info (специализация шаблонного класса) |
|
(C++20) | поддержка форматирования для local_info (специализация шаблона класса) |
|
(C++20) | поддержка форматирования для zoned_time (специализация шаблона класса) |
|
(C++23) | поддержка форматирования для basic_stacktrace (специализация шаблона класса) |
|
(C++23) | поддержка форматирования для stacktrace_entry (специализация шаблона класса) |
|
(C++23) | поддержка форматирования для thread::id (специализация шаблона класса) |
|
(C++23) | поддержка форматирования для vector<bool>::reference (специализация шаблона класса) |
|
(C++23) | поддержка форматирования для pair и tuple (специализация шаблона класса) |
|
(C++23) | поддержка форматирования для диапазонов (специализация шаблона класса) |
Примечания
| Макрокоманда для проверки наличия функции | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_lib_format_uchar | 202311L |
(C++20) (DR) | Форматирование кодовых единиц как целых без знака |
Пример
#include <algorithm>
#include <format>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string_view>
struct QuotableString : std::string_view
{};
template<>
struct std::formatter<QuotableString, char>
{
bool quoted = false;
template<class ParseContext>
constexpr ParseContext::iterator parse(ParseContext& ctx)
{
auto it = ctx.begin();
if (it == ctx.end())
return it;
if (*it == '#')
{
quoted = true;
++it;
}
if (*it != '}')
throw std::format_error("Invalid format args for QuotableString.");
return it;
}
template<class FmtContext>
FmtContext::iterator format(QuotableString s, FmtContext& ctx) const
{
std::ostringstream out;
if (quoted)
out << std::quoted(s);
else
out << s;
return std::ranges::copy(std::move(out).str(), ctx.out()).out;
}
};
int main()
{
QuotableString a("be"), a2(R"( " be " )");
QuotableString b("a question");
std::cout << std::format("To {0} or not to {0}, that is {1}.\n", a, b);
std::cout << std::format("To {0:} or not to {0:}, that is {1:}.\n", a, b);
std::cout << std::format("To {0:#} or not to {0:#}, that is {1:#}.\n", a2, b);
}Вывод:
To be or not to be, that is a question. To be or not to be, that is a question. To " \" be \" " or not to " \" be \" ", that is "a question".
Отчёты об ошибках
Следующие исправления, меняющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применимо к | Поведение как опубликовано | Правильное поведение |
|---|---|---|---|
| P2909R4 | C++20 |
char или wchar_t могут быть отформатированы как значения целых без знака, выходящие за пределы диапазона | кодовые единицы преобразуются в соответствующий тип целого без знака перед форматированием |
| LWG 3721 | C++20 | нуль недопустим для поля ширины в стандартной спецификации форматирования | нуль допустим, если указан через поле замены |
См. также
|
(C++20)(C++20)(C++20) | состояние форматирования, включая все аргументы форматирования и итератор вывода (шаблон класса) |
|
(C++23) | указывает, что тип форматируемый, то есть он специализируется std::formatter и предоставляет методы parse и format (концепция) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/utility/format/formatter