13

在 C++20 中-如何使用户定义的类型兼容std::format

例如,假设我有一个名为Point

struct Point {
    int x;
    int y;
};

operator<<定义:

inline std::ostream&
operator<<(std::ostream& o, Point pt)
{ return o << "[" << pt.x << << ", " << pt.y << "]"; }

那么下面的程序会输出Hello [3, 4]!吗?

int main() {
   Point pt{3,4};
   std::cout << std::format("Hello {}!\n", pt);
}

如果是 - 为什么以及如何?

如果不是 - 我必须在 to 的定义中添加什么才能Point使其工作?

4

2 回答 2

14

std::format不支持operator<<,您需要formatter为您的类型 ( Point) 提供专门化。最简单的方法是重用现有的格式化程序之一,例如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);
  }
};

std::string这将为您提供开箱即用支持的所有格式规范。Point这是一个使用 '~' 填充到 10 个字符的居中对齐格式示例:

auto s = std::format("{:~^10}", Point{1, 2});
// s == "~~[1, 2]~~"

使用 iostreams 实现这一点并非易事。

于 2020-01-26T01:41:45.357 回答
7

你必须专攻std::formatter你的类型。

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);
        }
    };
}

我不认为 ostream 运营商会工作,但我没有消息来源支持这一说法。

于 2020-01-25T12:56:20.640 回答