
std::format это большое и мощное дополнение в C ++ 20, которое позволяет нам эффективно форматировать текст в строки. Он добавляет форматирование в стиле Python с безопасностью и простотой использования.
В этой статье будет показано, как реализовать пользовательские форматеры, которые вписываются в эту новую std::formatархитектуру.
Краткое введение в std::format Для просмотра ссылки Войди или Зарегистрируйся
Вот пример Hello World:
Код:
#include <format>
#include <iostream>
#include <chrono>
int main() {
auto ym = std::chrono::year { 2022 } / std::chrono::July;
std::string msg = std::format("{:*^10}\n{:*>10}\nin{}!", "hello", "world", ym);
std::cout << msg;
}
Вывод:
Код:
**hello***
*****world
in2022/Jul!
Как вы можете видеть, у нас есть заполнители аргументов, которые расширяются и форматируются в std::string объект. Более того, у нас есть различные Для просмотра ссылки Войди
Существующие форматеры Для просмотра ссылки Войди или Зарегистрируйся
По умолчанию std::formatподдерживаются следующие типы:- char, wchar_t
- строковые типы - включая std::basic_string, std::basic_string_view, массивы символов, строковые литералы
- арифметические типы
- и указатели: void*, const void*и nullptr_t
Когда вы вызываете:
Код:
std::cout << std::format("10 = {}, 42 = {:10}\n", 10, 42);
Вызов создаст два форматера, по одному для каждого аргумента. Они отвечают за синтаксический анализ спецификатора формата и форматирование значения в выходных данных.
Специализации для форматировщиков:
Код:
template<> struct formatter<char, char>;
template<> struct formatter<char, wchar_t>;
template<> struct formatter<wchar_t, wchar_t>;
Для каждого charT- специализации строкового типа.
Код:
template<> struct formatter<charT*, charT>;
template<> struct formatter<const charT*, charT>;
template<size_t N> struct formatter<const charT[N], charT>;
template<class traits, class Allocator>
struct formatter<basic_string<charT, traits, Allocator>, charT>;
template<class traits>
struct formatter<basic_string_view<charT, traits>, charT>;
Для каждого charT, для каждого cv-неквалифицированного арифметического типа ArithmeticT , отличного от char, wchar_t, char8_t, char16_t, или char32_t, специализации:
Код:
template<> struct formatter<ArithmeticT, charT>;
Для каждого charTтипа специализации типа указателя:
Код:
template<> struct formatter<nullptr_t, charT>;
template<> struct formatter<void*, charT>;
template<> struct formatter<const void*, charT>;
Например, если вы хотите напечатать указатель:
Код:
int val = 10;
std::cout << std::format("val = {}, &val = {}\n", val, &val);
Это не сработает, и вы получите ошибку компилятора (не короткую, но, по крайней мере, описательную), которая:
Код:
auto std::make_format_args<std::format_context,int,int*>(const int &,int *const &)'
was being compiled and failed to find the required specializations...
Это потому, что мы пытались печататьint*, но библиотека поддерживает только void*. Мы можем исправить это, написав:
Код:
int val = 10;
std::cout << std::format("val = {}, &val = {}\n", val, static_cast<void*>(&val));
И вывод может быть (MSVC, x64, Debug):
Код:
val = 10, &val = 0xf5e64ff2c4
В {fmt}библиотеке есть даже утилита, но ее нет в стандарте.
Код:
template<typename T> auto fmt::ptr(T p) -> const void*
Хорошо, но как тогда насчет пользовательских типов?
Для потоков вы могли переопределить operator <<, и это сработало. Неужели это тоже так просто std::format?