使用 libfmt 打印或格式化自定义类型的简单方法是什么?



假设我定义了某种类型,例如

struct Foo { int a; float b; };

如果我想将其流式传输到ostream,我会编写一个operator<<函数,例如:

std::ostream& operator<<(std::ostream& os, const Foo& foo)
{
return os << '(' << a << ',' << b << ')';
}

现在我想做同样的事情,但在fmt::format()fmt::print()调用中。如果我写:

fmt::print("{}n", foo);

我会得到一堆错误,以这样的东西结束:

/path/to/fmt/core.h:1073:9: error: static assertion failed: Cannot format argument. 
To make type T formattable provide a formatter<T> specialization:
https://fmt.dev/latest/api.html#formatting-user-defined-types

好吧,我去那里,我看到了很多例子,其中第一个已经有点复杂了。我能写什么最简单的东西来实现我想要的?

为了简化示例,假设您只愿意接受{}格式说明符,而不需要任何额外的字符串来控制打印效果。在这种情况下,您将写下:

template <> class fmt::formatter<Foo> {
public:
constexpr auto parse (format_parse_context& ctx) { return ctx.begin(); }
template <typename Context>
constexpr auto format (Foo const& foo, Context& ctx) const {
return format_to(ctx.out(), "({}, {})", foo.a, foo.b);  // --== KEY LINE ==--
}
};

就是这样。有点巴洛克风格,你不能去掉第一种方法(为什么?…(,但也没那么可怕。从这里复制粘贴此片段;将Foo替换为您的类型;并重写KEY LINE上的实际格式化命令。

完整示例程序:

#include <fmt/format.h>
struct Foo { int a; float b; };
template <>
class fmt::formatter<Foo> {
public:
constexpr auto parse (format_parse_context& ctx) { return ctx.begin(); }
template <typename Context>
constexpr auto format (Foo const& foo, Context& ctx) const {
return format_to(ctx.out(), "({},{})", foo.a, foo.b);
}
};
int main () {
Foo foo {123, 4.56};
fmt::print("{}n", foo);
}

看看它在GodBolt上的工作。

这也适用:

#include "spdlog/fmt/ostr.h"
struct Foo { int a; float b; };
std::ostream& operator<<(std::ostream& os, const Foo& foo) {
return os << "(" << foo.a << "," << foo.b << ")";
}
int main () {
Foo foo {123, 4.56};
fmt::print("{}n", foo);
}

Godbolt:https://godbolt.org/z/vrEWGP1fn

最新更新