c++c++20fmtstdformat

std::format of user-defined types?


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?


Solution

  • 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) const {
        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.