{"id":973,"date":"2015-02-02T01:02:18","date_gmt":"2015-02-02T09:02:18","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=973"},"modified":"2015-06-30T21:17:12","modified_gmt":"2015-07-01T04:17:12","slug":"how-to-print-anything-in-c-part-5","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=973","title":{"rendered":"How to print anything in C++ (part 5)"},"content":{"rendered":"<p><a href=\"https:\/\/www.elbeno.com\/blog\/?p=951\">Part 1<\/a> <a href=\"https:\/\/www.elbeno.com\/blog\/?p=958\">Part 2<\/a> <a href=\"https:\/\/www.elbeno.com\/blog\/?p=964\">Part 3<\/a> <a href=\"https:\/\/www.elbeno.com\/blog\/?p=967\">Part 4<\/a> <a href=\"https:\/\/www.elbeno.com\/blog\/?p=973\">Part 5<\/a> <a href=\"https:\/\/www.elbeno.com\/blog\/?p=993\">Postscript<\/a><\/p>\n<p>So far, we can print containers, but what about arrays? And what about &#8220;pretty-printing&#8221; strings &#8211; perhaps we need to wrap them with quotes. Well, we know that with the existing code, both arrays and strings count as outputtable. Both <code>std::string<\/code> and <code>char*<\/code> (and its variously <code>const<\/code> friends) can be passed to <code>operator&lt;&lt;<\/code>, and so can arrays, because they decay to pointers.<\/p>\n<p>So, we should be able to deal with this using common-or-garden specialization on <code>stringifier_select<\/code>. Specializing for <code>std::string<\/code> is easy:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename C, typename T, typename A>\r\nstruct stringifier_select<std::basic_string<C,T,A>, \r\n                          is_outputtable_tag>\r\n{\r\n  using S = std::basic_string<C,T,A>;\r\n  explicit stringifier_select(const S& t) : m_t(t) {}\r\n\r\n  std::ostream& output(std::ostream& s) const\r\n  {\r\n    return s << C('\\\"') << m_t << C('\\\"');\r\n  }\r\n\r\n  const S&#038; m_t;\r\n};\r\n<\/pre>\n<p>And specializing for the other <code>char*<\/code> related types is also as easy, albeit verbose because of dealing with <code>char*<\/code>, <code>const char*<\/code>, <code>char* const<\/code> and <code>const char* const<\/code>.<\/p>\n<p>Specializing for arrays of <code>char<\/code> is just as easy. This time we have just the array size as a template argument. And once again, there is a specialization for arrays of <code>const char<\/code> that is identical.<\/p>\n<pre lang=\"cpp\">\r\ntemplate <size_t N>\r\nstruct stringifier_select<char[N], is_outputtable_tag>\r\n{\r\n  using S = char[N];\r\n  explicit stringifier_select(const S& t) : m_t(t) {}\r\n\r\n  std::ostream& output(std::ostream& s) const\r\n  {\r\n    return s << '\\\"' << m_t << '\\\"';\r\n  }\r\n\r\n  const S&#038; m_t;\r\n};\r\n<\/pre>\n<p>Specializing for arrays (other than of <code>char<\/code>) is also easy, and gives us a chance to abstract out the code that we used for the iterable printing. By happy circumstance (i.e. by design!), arrays support <code>std::begin()<\/code> and <code>std::end()<\/code>, so we can write the following:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nstd::ostream& output_iterable(std::ostream& s, const T& t)\r\n{\r\n  s << iterable_opener<T>()(t);\r\n  auto b = std::begin(t);\r\n  auto e = std::end(t);\r\n  if (b != e)\r\n    s << prettyprint(*b);\r\n  std::for_each(++b, e,\r\n                [&#038;s, &#038;t] (auto&#038; e)\r\n                { s << iterable_separator<T>()(t)\r\n                    << prettyprint(e); });\r\n  return s << iterable_closer<T>()(t);\r\n}\r\n\r\ntemplate <typename T, size_t N>\r\nstruct stringifier_select<T[N], is_outputtable_tag>\r\n{\r\n  using S = T[N];\r\n  explicit stringifier_select(const S& t) : m_t(t) {}\r\n\r\n  std::ostream& output(std::ostream& s) const\r\n  {\r\n    return output_iterable<T[N]>(s, m_t);\r\n  }\r\n\r\n  const S& m_t;\r\n};\r\n<\/pre>\n<p>And the code for printing iterable things changes likewise. Unlike the situation with <code>char*<\/code>, we don't need to deal with <code>const<\/code> and non-<code>const<\/code> separately because here, <code>T<\/code> itself is inferred to be <code>const<\/code> or not.<\/p>\n<p>And that's pretty much it - just a couple more things to add. I mentioned enum classes back in <a href=\"https:\/\/www.elbeno.com\/blog\/?p=951\">part 1<\/a>, and here's how we print out their values:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nstruct stringifier_select<T, is_enum_tag>\r\n{\r\n  explicit stringifier_select(T t) : m_t(t) {}\r\n\r\n  std::ostream& output(std::ostream& s) const\r\n  {\r\n    return s << static_cast<std::underlying_type_t<T>>(m_t);\r\n  }\r\n\r\n  T m_t;\r\n};\r\n<\/pre>\n<p>Simple. Two final things to add: first, specialize for pretty-printing <code>bool<\/code> equivalently to using <code>std::boolalpha<\/code>; second, distinguish a few \"unprintable\" things and output something for them - classes without <code>operator&lt;&lt;<\/code>, unions, <code>nullptr<\/code>. The code that does this is very similar to what we've already seen.<\/p>\n<p>So now, we can pretty-print all \"normally\" printable things, containers, <code>pair<\/code>s and <code>tuple<\/code>s, callable things, certain unprintables that we can meaningfully label, and really unprintable things with a fallback. I think that'll do for the time being. It's been a fun journey, exploring TMP techniques, C++ type support, mapping over <code>tuple<\/code>s, and the amazing <code>void_t<\/code>.<\/p>\n<p>You can find all the resulting code from this exercise <a href=\"https:\/\/github.com\/elbeno\/pretty-print\">on github<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Part 1 Part 2 Part 3 Part 4 Part 5 Postscript So far, we can print containers, but what about arrays? And what about &#8220;pretty-printing&#8221; strings &#8211; perhaps we need to wrap them with quotes. Well, we know that with the existing code, both arrays and strings count as outputtable&#8230;.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22,8],"tags":[],"class_list":["post-973","post","type-post","status-publish","format-standard","hentry","category-cpp","category-programming"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/973","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=973"}],"version-history":[{"count":12,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/973\/revisions"}],"predecessor-version":[{"id":996,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/973\/revisions\/996"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=973"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=973"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=973"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}