Spec-Zone.ru › C++

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>, которые потребовали бы преобразования кодировок, отключены.

Каждая специализация форматировщика для строкового или символьного типа дополнительно предоставляет общедоступную нестатическую функцию член constexpr void set_debug_format(); , которая изменяет состояние объекта форматировщика, чтобы он форматировал значения как экранированные и заключённые в кавычки, как если бы тип спецификатора форматирования, проанализированного последним вызовом parse , был ?.

(с 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; в противном случае вывод определяется реализацией.
  • P: аналогично p, за исключением того, что использует заглавные буквы для цифр выше 9 и префикс основания 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: ["ẹ́"]

Стандартные специализации для типов библиотеки

std::formatter<std::chrono::duration>
(C++20)
Поддержка форматирования для duration
(специализация шаблонного класса)
std::formatter<std::chrono::sys_time>
(C++20)
Поддержка форматирования для sys_time
(специализация шаблонного класса)
std::formatter<std::chrono::utc_time>
(C++20)
Поддержка форматирования для utc_time
(специализация шаблонного класса)
std::formatter<std::chrono::tai_time>
(C++20)
Поддержка форматирования для tai_time
(специализация шаблонного класса)
std::formatter<std::chrono::gps_time>
(C++20)
Поддержка форматирования для gps_time
(специализация шаблонного класса)
std::formatter<std::chrono::file_time>
(C++20)
Поддержка форматирования для file_time
(специализация шаблонного класса)
std::formatter<std::chrono::local_time>
(C++20)
Поддержка форматирования для local_time
(специализация шаблонного класса)
std::formatter<std::chrono::day>
(C++20)
Поддержка форматирования для day
(специализация шаблонного класса)
std::formatter<std::chrono::month>
(C++20)
Поддержка форматирования для month
(специализация шаблонного класса)
std::formatter<std::chrono::year>
(C++20)
Поддержка форматирования для year
(специализация шаблонного класса)
std::formatter<std::chrono::weekday>
(C++20)
Поддержка форматирования для weekday
(специализация шаблонного класса)
std::formatter<std::chrono::weekday_indexed>
(C++20)
Поддержка форматирования для weekday_indexed
(специализация шаблонного класса)
std::formatter<std::chrono::weekday_last>
(C++20)
Поддержка форматирования для weekday_last
(специализация шаблонного класса)
std::formatter<std::chrono::month_day>
(C++20)
Поддержка форматирования для month_day
(специализация шаблонного класса)
std::formatter<std::chrono::month_day_last>
(C++20)
Поддержка форматирования для month_day_last
(специализация шаблонного класса)
std::formatter<std::chrono::month_weekday>
(C++20)
Поддержка форматирования для month_weekday
(специализация шаблонного класса)
std::formatter<std::chrono::month_weekday_last>
(C++20)
Поддержка форматирования для month_weekday_last
(специализация шаблонного класса)
std::formatter<std::chrono::year_month>
(C++20)
Поддержка форматирования для year_month
(специализация шаблонного класса)
std::formatter<std::chrono::year_month_day>
(C++20)
Поддержка форматирования для year_month_day
(специализация шаблонного класса)
std::formatter<std::chrono::year_month_day_last>
(C++20)
Поддержка форматирования для year_month_day_last
(специализация шаблонного класса)
std::formatter<std::chrono::year_month_weekday>
(C++20)
Поддержка форматирования для year_month_weekday
(специализация шаблонного класса)
std::formatter<std::chrono::year_month_weekday_last>
(C++20)
Поддержка форматирования для year_month_weekday_last
(специализация шаблонного класса)
std::formatter<std::chrono::hh_mm_ss>
(C++20)
Поддержка форматирования для hh_mm_ss
(специализация шаблонного класса)
std::formatter<std::chrono::sys_info>
(C++20)
Поддержка форматирования для sys_info
(специализация шаблонного класса)
std::formatter<std::chrono::local_info>
(C++20)
поддержка форматирования для local_info
(специализация шаблона класса)
std::formatter<std::chrono::zoned_time>
(C++20)
поддержка форматирования для zoned_time
(специализация шаблона класса)
std::formatter<std::basic_stacktrace>
(C++23)
поддержка форматирования для basic_stacktrace
(специализация шаблона класса)
std::formatter<std::stacktrace_entry>
(C++23)
поддержка форматирования для stacktrace_entry
(специализация шаблона класса)
std::formatter<std::thread::id>
(C++23)
поддержка форматирования для thread::id
(специализация шаблона класса)
std::formatter<std::vector<bool>::reference>
(C++23)
поддержка форматирования для vector<bool>::reference
(специализация шаблона класса)
std::formatter<pair-or-tuple>
(C++23)
поддержка форматирования для pair и tuple
(специализация шаблона класса)
std::formatter<range>
(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 нуль недопустим для поля ширины
в стандартной спецификации форматирования
нуль допустим, если указан
через поле замены

См. также

basic_format_contextformat_contextwformat_context
(C++20)(C++20)(C++20)
состояние форматирования, включая все аргументы форматирования и итератор вывода
(шаблон класса)
formattable
(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

Spec-Zone.ru

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