In order to use C++20's format capabilities with custom types, we have to provide template specializations of std::formatter for every type we want to format. The nice thing about this approach is that formatting support for any given class can be added in a non-intrusive way.
However, what if I want to format a polymorphic type? So as a quick example, let's consider
struct Fruit {};
struct Apple : Fruit {};
struct Banana : Fruit {};
So assume that I have an object of type Fruit & and want to format it, but I want the formatted output to depend on the exact type of the object. That is, I want Apple and Banana to be formatted differently. Adding specializations std::formatter<Apple> and std::formatter<Banana> helps only if we have objects of type Apple or Banana but they won't be used for a Fruit &. Of course, we could specialize std::formatter<Fruit> but this would then always be used for Fruit & regardless of whether the underlying object is an Apple or a Banana.
We could also do something like (Godbolt)
template <typename F>
requires std::is_base_of_v<Fruit, F>
struct std::formatter<F> {
constexpr auto parse(std::format_parse_context& ctx) {
return ctx.begin();
}
auto format(const F& obj, std::format_context& ctx) const {
return std::format_to(ctx.out(), "{}", "Some kind of Fruit");
}
};
but in order to achieve the desired output, Fruit would need a virtual function that is being called to do the formatting which can be called in this std::formatter specialization. However, this would require intrusive changes to the classes.
Hence, my question is: is there any way to obtain a "virtual template specialization" such that I can implement formatting support for polymorphic objects in a non-intrusive way that allows for sub-classes to overwrite the formatting of their parent classes?
virtualmethods, or by a "visitor", but then, you have to know the set of types to consider...Fruit &as that would require a specialization forstd::formatter<Fruit>and as you suggested,Fruit::description()doesn't exist.