We can customize the (printing) format of a given class by using the specialization of formatter.
#include <format>
#include <iostream>
struct Frac {
int a, b;
};
template <>
struct std::formatter<Frac> : std::formatter<string_view> {
// parse() is inherited from the base class std::formatter<string_view>
// * an efficient solution:
auto format(const Frac& frac, std::format_context& ctx) const {
return std::format_to(ctx.out(), "{}/{}", frac.a, frac.b);
}
// the same functionality as above, but inefficient due to the temporary string
// auto format(const Frac& frac, std::format_context& ctx) const {
// std::string temp;
// std::format_to(std::back_inserter(temp), "{}/{}",
// frac.a, frac.b);
// return std::formatter<string_view>::format(temp, ctx);
// }
};
void print(std::string_view fmt,auto&&...args){
std::cout << std::vformat(fmt, std::make_format_args(std::forward<decltype(args)>(args)...));
}
int main()
{
Frac f{ 1,10 };
print("{}", f); // prints "1/10"
}
ctx
: provides access to formatting state consisting of the formatting arguments and the output iterator.ctx.out()
: the iterator to the output bufferstd::format_to()
: append parts of the formatted output to the target destination.