How to print anything in C++ (postscript)

Part 1 Part 2 Part 3 Part 4 Part 5 Postscript

Refactoring! My initial plan for customizing opener/closer/separator for containers turned out to be unwieldy: I realized that it wouldn’t be possible for me to provide default specializations and also allow clients to specialize. Also, you may have noticed that the code for printing pairs, tuples, strings and arrays didn’t allow for customization at all. So I reworked the customization, allowing a formatter object as a parameter to prettyprint() and providing a default one:

template <typename T>
inline stringifier<std::remove_reference_t<T>, default_formatter>
prettyprint(T&& t)
  return stringifier<std::remove_reference_t<T>, default_formatter>(
      std::forward<T>(t), default_formatter());
template <typename T, typename F>
inline stringifier<std::remove_reference_t<T>, F>
prettyprint(T&& t, F&& f)
  return stringifier<std::remove_reference_t<T>, F>(
      std::forward<T>(t), std::forward<F>(f));

The default_formatter looks like this:

struct default_formatter
  // default separator, opener and closer
  template <typename T>
  constexpr const char* separator(const T&) const
  { return ","; }
  template <typename T>
  constexpr const char* opener(const T&) const
  { return "{"; }
  template <typename T>
  constexpr const char* closer(const T&) const
  { return "}"; }
  // use [] for vectors
  template <typename T>
  constexpr const char* opener(const std::vector<T>&) const
  { return "["; }
  template <typename T>
  constexpr const char* closer(const std::vector<T>&) const
  { return "]"; }
  // etc (more omitted)

And now I can pass the formatter object through to each specialization of stringifier_select, and use it appropriately for pairs, tuples, strings and arrays, as well as iterables. When I want to override the formatter, I simply specify a new formatter type, implement the opener/closer/separator functions for the type in question the way I want to, and pass an instance to prettyprint.

Leave a Reply