In C++20 - how do you make a user-defined type compatible with std::format?
For example, let's say I have a type called Point:
struct Point {
    int x;
    int y;
};
with its operator<< defined:
inline std::ostream&
operator<<(std::ostream& o, Point pt)
{ return o << "[" << pt.x << << ", " << pt.y << "]"; }
then will the following program output Hello [3, 4]!?
int main() {
   Point pt{3,4};
   std::cout << std::format("Hello {}!\n", pt);
}
If yes - why and how?
If no - what do I have to add to the definition of Point to to make it work?
std::format doesn't support operator<<, you need to provide a formatter specialization for your type (Point) instead. The easiest way to do it is by reusing one of existing formatters, e.g. std::formatter<std::string>:
template <>
struct std::formatter<Point> : std::formatter<std::string> {
  auto format(Point p, format_context& ctx) {
    return formatter<string>::format(
      std::format("[{}, {}]", p.x, p.y), ctx);
  }
};
This will give you all format specifications supported by std::string out of the box. Here is an example of formatting Point with center alignment padded with '~' to 10 characters:
auto s = std::format("{:~^10}", Point{1, 2});
// s == "~~[1, 2]~~"
which is nontrivial to achieve with iostreams.
You have to specialize std::formatter for your type.
namespace std
{
    template<class CharT>
    struct formatter<Point, CharT>
    {  
        template <typename FormatParseContext>
        auto parse(FormatParseContext& pc)
        {
            // parse formatter args like padding, precision if you support it
            return pc.end(); // returns the iterator to the last parsed character in the format string, in this case we just swallow everything
        }
        template<typename FormatContext>
        auto format(Point p, FormatContext& fc) 
        {
            return std::format_to(fc.out(), "[{}, {}]", p.x, p.y);
        }
    };
}
I don't think the ostream operator will work but I have no sources to support this claim.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With