c++format

What are the correct parameters and return types for std::formatter::format specialization?


#include <format>
#include <print>
#include <array>

struct Point {
    int x = 0;
    int y = 0;
    int z = 0;
};

template <>
struct std::formatter<Point> : std::formatter<int> {
    // v1
    //auto format(const Point& p, auto& ctx) const {
    //  const auto [x, y, z] = p;
    //  return std::format_to(ctx.out(), "(x={}, y={}, z={})", x, y, z);
    //}

    // v2
    auto format(const Point& p, std::format_context& ctx) const {
        const auto [x, y, z] = p;
        return std::format_to(ctx.out(), "(x={}, y={}, z={})", x, y, z);
    }
};

int main() {
    const Point p{ 1, 2, 3 };
    std::println("{}", p); // compiles both in v1, and v2

    const auto points = std::to_array<Point>({ {1, 2, 3}, {4, 5, 6}, {7, 8, 9} });
    std::println("{}", points); // compiles only in v1
}

What are the correct parameter types for format?

I see auto& ctx used in some examples, but I’d like to explicitly spell out the type.

What is the correct return type of format?

Should it always be an iterator? If so, which one exactly?

I'm using MSVC (cl version is 19.44.35215) c++23/preview


Solution

  • I see auto& ctx used in some examples, but I’d like to explicitly spell out the type.

    While the explicit spelling of std::format_context& appears to be fine (and should be), unfortunately, the current standard has the unintended consequence of not being able to enable formatting ranges for such custom types.

    That is, using format_context& as a function argument does not automatically enable support for formatting ranges of Points, such as vector<Point>, in your example.

    So you may still need to template the parameters at present, for example:

    auto format(const Point& p, auto& ctx) const;
    

    Or more informative (standard style):

    template<class FormatContext>
    typename FormatContext::iterator
      format(const Point& p, FormatContext& ctx) const;