Expression | Return type | Requirement |
f.parse(pc) | PC::iterator | Parses format-spec ([format.string])
for type T
in the range [pc.begin(), pc.end())
until the first unmatched character.
Stores the parsed format specifiers in *this and
returns an iterator past the end of the parsed range. |
f.format(t, fc) | FC::iterator | Formats t according to the specifiers stored in *this,
writes the output to fc.out() and
returns an iterator past the end of the output range. The output shall only depend on
t,
fc.locale(),
and the range [pc.begin(), pc.end())
from the last call to f.parse(pc). |
f.format(u, fc) | FC::iterator | As above, but does not modify u. |
template<> struct formatter<char, char>; template<> struct formatter<char, wchar_t>; template<> struct formatter<wchar_t, wchar_t>;
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>;
template<> struct formatter<ArithmeticT, charT>;
template<> struct formatter<nullptr_t, charT>; template<> struct formatter<void*, charT>; template<> struct formatter<const void*, charT>;
#include <format> enum color { red, green, blue }; const char* color_names[] = { "red", "green", "blue" }; template<> struct std::formatter<color> : std::formatter<const char*> { auto format(color c, format_context& ctx) { return formatter<const char*>::format(color_names[c], ctx); } }; struct err {}; std::string s0 = std::format("{}", 42); // OK, library-provided formatter std::string s1 = std::format("{}", L"foo"); // error: disabled formatter std::string s2 = std::format("{}", red); // OK, user-provided formatter std::string s3 = std::format("{}", err{}); // error: disabled formatter— end example
namespace std { template<class charT> class basic_format_parse_context { public: using char_type = charT; using const_iterator = typename basic_string_view<charT>::const_iterator; using iterator = const_iterator; private: iterator begin_; // exposition only iterator end_; // exposition only enum indexing { unknown, manual, automatic }; // exposition only indexing indexing_; // exposition only size_t next_arg_id_; // exposition only size_t num_args_; // exposition only public: constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt, size_t num_args = 0) noexcept; basic_format_parse_context(const basic_format_parse_context&) = delete; basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; constexpr const_iterator begin() const noexcept; constexpr const_iterator end() const noexcept; constexpr void advance_to(const_iterator it); constexpr size_t next_arg_id(); constexpr void check_arg_id(size_t id); }; }
constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
size_t num_args = 0) noexcept;
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr void advance_to(const_iterator it);
constexpr size_t next_arg_id();
if (indexing_ == unknown) indexing_ = automatic; return next_arg_id_++;
constexpr void check_arg_id(size_t id);
namespace std { template<class Out, class charT> class basic_format_context { basic_format_args<basic_format_context> args_; // exposition only Out out_; // exposition only public: using iterator = Out; using char_type = charT; template<class T> using formatter_type = formatter<T, charT>; basic_format_arg<basic_format_context> arg(size_t id) const; std::locale locale(); iterator out(); void advance_to(iterator it); }; }
basic_format_arg<basic_format_context> arg(size_t id) const;
std::locale locale();
iterator out();
void advance_to(iterator it);
struct S { int value; }; template<> struct std::formatter<S> { size_t width_arg_id = 0; // Parses a width argument id in the format { digit }. constexpr auto parse(format_parse_context& ctx) { auto iter = ctx.begin(); auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; }; if (get_char() != '{') return iter; ++iter; char c = get_char(); if (!isdigit(c) || (++iter, get_char()) != '}') throw format_error("invalid format"); width_arg_id = c - '0'; ctx.check_arg_id(width_arg_id); return ++iter; } // Formats an S with width given by the argument width_arg_id. auto format(S s, format_context& ctx) { int width = visit_format_arg([](auto value) -> int { if constexpr (!is_integral_v<decltype(value)>) throw format_error("width is not integral"); else if (value < 0 || value > numeric_limits<int>::max()) throw format_error("invalid width"); else return value; }, ctx.arg(width_arg_id)); return format_to(ctx.out(), "{0:x<{1}}", s.value, width); } }; std::string s = std::format("{0:{1}}", S{42}, 10); // value of s is "xxxxxxxx42"— end example