Спецификация стандартного формата (начиная с C++20)
Для базовых типов и строковых типов спецификация формата основана на спецификации формата в Python.
Синтаксис спецификаций формата:
fill-and-align (необязательно) sign (необязательно) #(необязательно) 0(необязательно) width (необязательно) precision (необязательно) L(необязательно) type (необязательно) |
Параметры sign, # и 0 допустимы только при использовании типа представления целого числа или числа с плавающей точкой.
Заполнение и выравнивание
fill-and-align — это необязательный символ заполнения (им может быть любой символ, кроме { или }), за которым следует один из параметров выравнивания <, >, ^.
Если символ заполнения не указан, по умолчанию используется пробел. В спецификации формата для кодировки Unicode символ заполнения должен соответствовать одному скалярному значению Unicode.
Параметры выравнивания имеют следующее значение:
-
<: принудительно выравнивает форматируемый аргумент по началу доступного пространства, вставляя n символов заполнения после форматируемого аргумента. Это значение используется по умолчанию, если применяется тип представления, отличный от целочисленного и типа с плавающей точкой. -
>: принудительно выравнивает форматируемый аргумент по концу доступного пространства, вставляя n символов заполнения перед форматируемым аргументом. Это значение используется по умолчанию, если применяется тип представления целого числа или числа с плавающей точкой. -
^: принудительно выравнивает форматируемый аргумент по центру доступного пространства, вставляя ⌊n/2⌋ символов перед форматируемым аргументом и ⌈n/2⌉ символов после него.
Во всех случаях n — это разность между минимальной шириной поля (указанной с помощью width) и расчётной шириной форматируемого аргумента либо 0, если разность меньше 0.
#include <cassert>
#include <format>
int main()
{
char c = 120;
assert(std::format("{:6}", 42) == " 42");
assert(std::format("{:6}", 'x') == "x ");
assert(std::format("{:*<6}", 'x') == "x*****");
assert(std::format("{:*>6}", 'x') == "*****x");
assert(std::format("{:*^6}", 'x') == "**x***");
assert(std::format("{:6d}", c) == " 120");
assert(std::format("{:6}", true) == "true ");
}
Знак, # и 0
Параметр sign может принимать одно из следующих значений:
-
+: указывает, что знак следует использовать как для неотрицательных, так и для отрицательных чисел. Для неотрицательных чисел перед выходным значением вставляется знак+. -
-: указывает, что знак следует использовать только для отрицательных чисел (такое поведение используется по умолчанию). - пробел: указывает, что для неотрицательных чисел следует использовать начальный пробел, а для отрицательных — знак минус.
Отрицательный ноль считается отрицательным числом.
Параметр sign применяется к бесконечности и NaN типа с плавающей точкой.
#include <cassert>
#include <format>
#include <limits>
int main()
{
double inf = std::numeric_limits<double>::infinity();
double nan = std::numeric_limits<double>::quiet_NaN();
assert(std::format("{0:},{0:+},{0:-},{0: }", 1) == "1,+1,1, 1");
assert(std::format("{0:},{0:+},{0:-},{0: }", -1) == "-1,-1,-1,-1");
assert(std::format("{0:},{0:+},{0:-},{0: }", inf) == "inf,+inf,inf, inf");
assert(std::format("{0:},{0:+},{0:-},{0: }", nan) == "nan,+nan,nan, nan");
}
Параметр # задаёт использование альтернативной формы при преобразовании.
- Для целочисленных типов при использовании двоичного, восьмеричного или шестнадцатеричного типа представления альтернативная форма добавляет к выходному значению префикс (
0b,0или0x) после символа знака (возможно, пробела), если он есть, либо в противном случае добавляет его перед выходным значением. - Для типов с плавающей точкой альтернативная форма приводит к тому, что результат преобразования конечных значений всегда содержит символ десятичной точки, даже если за ним не следуют цифры. Обычно символ десятичной точки появляется в результате этих преобразований только в том случае, если за ним следует цифра. Кроме того, при преобразованиях
gиGконечные нули не удаляются из результата.
Параметр 0 заполняет поле начальными нулями (после любого обозначения знака или основания) до ширины поля, за исключением случаев, когда он применяется к бесконечности или NaN. Если присутствуют символ 0 и параметр выравнивания, символ 0 игнорируется.
#include <cassert>
#include <format>
int main()
{
char c = 120;
assert(std::format("{:+06d}", c) == "+00120");
assert(std::format("{:#06x}", 0xa) == "0x000a");
assert(std::format("{:<06}", -42) == "-42 "); // 0 is ignored because of '<'
}
Ширина и точность
width — это положительное десятичное число или вложенное поле подстановки ({} или {n}). Если оно указано, то задаёт минимальную ширину поля.
precision — это точка (.), за которой следует неотрицательное десятичное число или вложенное поле подстановки. Это поле указывает точность или максимальный размер поля. Его можно использовать только с типами с плавающей точкой и строковыми типами.
- Для типов с плавающей точкой это поле задаёт точность форматирования.
- Для строковых типов оно задаёт верхнюю границу расчётной ширины (см. ниже) префикса строки, который будет скопирован в выходные данные. Для строки в кодировке Unicode в выходные данные копируется самый длинный префикс из целых расширенных графемных кластеров, расчётная ширина которого не превышает точность.
Если для width или precision используется вложенное поле подстановки, а соответствующий аргумент не имеет целочисленного типа(до C++23)стандартного знакового или беззнакового целочисленного типа(начиная с C++23) либо является отрицательным, выбрасывается исключение типа std::format_error.
float pi = 3.14f;
assert(std::format("{:10f}", pi) == " 3.140000"); // width = 10
assert(std::format("{:{}f}", pi, 10) == " 3.140000"); // width = 10
assert(std::format("{:.5f}", pi) == "3.14000"); // precision = 5
assert(std::format("{:.{}f}", pi, 5) == "3.14000"); // precision = 5
assert(std::format("{:10.5f}", pi) == " 3.14000"); // width = 10, precision = 5
assert(std::format("{:{}.{}f}", pi, 10, 5) == " 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имеет значение Fullwidth (F) или Wide (W) - U+4DC0 - U+4DFF (символы гексаграмм И Цзин)
- U+1F300 – U+1F5FF (различные символы и пиктограммы)
- U+1F900 – U+1F9FF (дополнительные символы и пиктограммы)
#include <cassert>
#include <format>
int main()
{
assert(std::format("{:.^5s}", "🐱") == ".🐱..");
assert(std::format("{:.5s}", "🐱🐱🐱") == "🐱🐱");
assert(std::format("{:.<5.5s}", "🐱🐱🐱") == "🐱🐱.");
}
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), где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), гдеprecision— заданная точность или 6, если точность не задана. -
E: то же, чтоe, за исключением того, что для обозначения экспоненты используетсяE. -
f,F: формирует выходные данные так, как если бы была вызвана функцияstd::to_chars(first, last, value, std::chars_format::fixed, precision), гдеprecision— заданная точность или 6, если точность не задана. -
g: формирует выходные данные так, как если бы была вызвана функцияstd::to_chars(first, last, value, std::chars_format::general, precision), гдеprecision— заданная точность или 6, если точность не задана. -
G: то же, чтоg, за исключением того, что для обозначения экспоненты используетсяE. - none: если задана точность, формирует выходные данные так, как если бы была вызвана функция
std::to_chars(first, last, value, std::chars_format::general, precision), где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) |
Форматирование экранированных символов и строкСимвол или строку можно форматировать в экранированном виде, чтобы сделать их более подходящими для отладки или ведения журналов. Экранирование выполняется следующим образом:
Экранированное представление строки формируется путём экранирования последовательностей кодовых единиц в строке, как описано выше, и заключения результата в двойные кавычки. Экранированное представление символа формируется путём его экранирования, как описано выше, и заключения результата в одинарные кавычки. Демонстрация в Compiler Explorer: #include <print>
int main()
{
std::println("[{:?}]", "h\tllo"); // prints: ["h\tllo"]
std::println("[{:?}]", "Спасибо, Виктор ♥!"); // prints: ["Спасибо, Виктор ♥!"]
std::println("[{:?}] [{:?}]", '\'', '"'); // prints: ['\'', '"']
// The following examples assume use of the UTF-8 encoding
std::println("[{:?}]", std::string("\0 \n \t \x02 \x1b", 9));
// prints: ["\u{0} \n \t \u{2} \u{1b}"]
std::println("[{:?}]", "\xc3\x28"); // invalid UTF-8
// prints: ["\x{c3}("]
std::println("[{:?}]", "\u0301"); // prints: ["\u{301}"]
std::println("[{:?}]", "\\\u0301"); // prints: ["\\\u{301}"]
std::println("[{:?}]", "e\u0301\u0323"); // prints: ["ẹ́"]
}
| (начиная с C++23) |
Примечания
В большинстве случаев синтаксис похож на старое форматирование %, с добавлением {} и использованием : вместо %. Например, "%03.2f" можно преобразовать в "{:03.2f}".
| Макрос проверки поддержки функции | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_lib_format_uchar | 202311L |
(C++20) (DR) | Форматирование кодовых единиц как беззнаковых целых чисел |
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применён к | Опубликованное поведение | Корректное поведение |
|---|---|---|---|
| LWG 3721 | C++20 | ноль не допускается в поле ширины в спецификации стандартного формата | ноль разрешён, если он указан через поле подстановки |
| P2909R4 | C++20 |
char или wchar_t могли форматироваться как беззнаковые целочисленные значения вне допустимого диапазона | перед таким форматированием кодовые единицы преобразуются в соответствующий беззнаковый тип |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/utility/format/spec