Custom class fmt::formatter for non const argument

65 Views Asked by At

I have a class:

class MyClass{
   public:
   std::string _cachedString;
   std::string_view get_string(){
      _cachedString = "abc";
      return _cachedString;
   }
};

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

    template <typename FormatContext>
    constexpr auto format( MyClass& t, FormatContext& ctx){
        return format_to(ctx.out(), "({})", t.get_string());
    }
};

I looked this up, and found that you need to pass const MyClass& t as argument to format function. But in my case, since I am modifying the object, I cannot. When I compile this code, I get this error:

 undefined reference to `fmt::v8::detail::value<fmt::v8::basic_format_context<fmt::v8::appender, char> >::value(fmt::v8::detail::unformattable_const)'

which goes away when I remove the line calling fmt::format on MyClass object. How to rectify this?

1

There are 1 best solutions below

0
vitaut On BEST ANSWER

You should make the format function itself const:

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

  template <typename FormatContext>
  constexpr auto format(MyClass& t, FormatContext& ctx) const {
    return format_to(ctx.out(), "({})", t.get_string());
  }
};

Otherwise your example works in recent versions of {fmt} (godbolt):

int main() {
  MyClass c;
  fmt::print("{}", c);
}

However, as @super correctly pointed out in the comments, a better solution is to make _cachedString mutable and get_string const:

class MyClass {
 public:
  mutable std::string _cachedString;

  std::string_view get_string() const {
    _cachedString = "abc";
    return _cachedString;
  }
};