如何使 `template<> struct fmt::formatter<Foo>` 成为 Foo 的友元

rtu*_*ado 3 c++ templates template-specialization fmt

我有一个Foo带有私有成员的类x,并且我希望能够打印Foovia的实例fmt::print

[演示]

#include <fmt/format.h>

class Foo {
public:
    explicit Foo(int i) : x{i} {}
private:
    int x{};
};

template<>
struct fmt::formatter<Foo> {
    template<typename ParseContext>
    constexpr auto parse(ParseContext& ctx) {
        return ctx.begin();
    }

    template<typename FormatContext>
    auto format(const Foo& foo, FormatContext& ctx) {
        return fmt::format_to(ctx.out(), "{}", foo.x);
    }
};

int main() {
    Foo foo{5};
    fmt::print("{}", foo);
}
Run Code Online (Sandbox Code Playgroud)

上面的代码存在尝试访问私有成员的问题Foo::x

<source>:19:52: error: 'int Foo::x' is private within this context
   19 |         return fmt::format_to(ctx.out(), "{}", foo.x);
      |                                                ~~~~^
Run Code Online (Sandbox Code Playgroud)

我评估了几个选项:

  1. 实现一个Foo::to_string方法(并从 中使用它format)。
    这是一个简单的选择,但我不想format需要使用to_string;我希望它可以直接在x.
  2. 提供一个get_x访问器(并从 中使用它format)。
    这也是一个简单的选择。format将在 上运行x。但是,我知道,很多时候,您不想为您的私有数据提供访问器。
  3. template<> struct fmt::formatter<Foo>个朋友Foo
    这是我真正想要的选择,只是我不知道如何实现它。

rtu*_*ado 5

添加friend struct fmt::formatter<Foo>Foo

[演示]

class Foo {
public:
    explicit Foo(int i) : x{i} {}
private:
    int x{};

    friend struct fmt::formatter<Foo>;
};
Run Code Online (Sandbox Code Playgroud)