'Specializing formatting for pointer to class

I need to provide format-magic to a class hierarchy and usually those things are passed around via pointer. This example here works currently on master:

#include <type_traits>
#include <sstream>
#include <fmt/format.h>
#include <fmt/ostream.h>

struct A {
  virtual ~A() {}
  virtual std::string name() const { return "A"; }
};

struct B : A {
  virtual std::string name() const { return "B"; }
};

template <typename T>
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, std::remove_const_t<std::remove_pointer_t<T>>>::value, char>> : fmt::formatter<std::string> {
  template <typename FormatCtx>
  auto format(const A* a, FormatCtx& ctx) {
    return fmt::formatter<std::string>::format(a->name(), ctx);
  }
};

template<class... T>
[[noreturn]] void err(fmt::format_string<T...> s, T&&... args) {
    throw std::logic_error(fmt::format(s, std::forward<T>(args)...));
}

int main() {
    A* a = new A();
    B* b = new B();
    const A* x = new A();
    const B* y = new B();
    fmt::print("{}, {}, {}, {}\n", a, b, x, y);
    std::ostringstream oss;
    fmt::print(oss, "{}\n", a);
    err("{}, {}, {}, {}\n", a, b, x, y);
}

However, when I'm going to the latest release 8.1.1, I'm getting:

error: static assertion failed: Formatting of non-void pointers is disallowed.

Now my question is: What's the plan here? Can I do this in future versions of fmt or is this more of an accident?

fmt


Solution 1:[1]

This is definitely a regression. Supporting a hierarchy of classes can be done as documented in https://fmt.dev/latest/api.html#formatting-user-defined-types using references instead of pointers:

#include <type_traits>
#include <fmt/format.h>

struct A {
  virtual ~A() {}
  virtual std::string name() const { return "A"; }
};

struct B : A {
  virtual std::string name() const { return "B"; }
};

template <typename T>
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
    fmt::formatter<std::string> {
  template <typename FormatCtx>
  auto format(const A& a, FormatCtx& ctx) {
    return fmt::formatter<std::string>::format(a.name(), ctx);
  }
};

int main() {
  B b;
  A& a = b;
  fmt::print("{}", a); // prints "B"
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1