{"id":958,"date":"2015-02-01T23:39:46","date_gmt":"2015-02-02T07:39:46","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=958"},"modified":"2015-06-30T21:17:35","modified_gmt":"2015-07-01T04:17:35","slug":"how-to-print-anything-in-c-part-2","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=958","title":{"rendered":"How to print anything in C++ (part 2)"},"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>We have a basic plan, and the ability to detect concrete types. But how can we detect whether an object supports output with <code>operator&lt;&lt;<\/code>? For this, there is a recently-discovered amazing trick. Here&#8217;s the code:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename...>\r\nusing void_t = void;\r\n\r\ntemplate <typename T>\r\nusing operator_output_t = decltype(std::cout << std::declval<T>());\r\n\r\ntemplate <typename T, typename = void>\r\nstruct has_operator_output : public std::false_type {};\r\n\r\ntemplate <typename T>\r\nstruct has_operator_output<T, void_t<operator_output_t<T>>> \r\n  : public std::true_type {};\r\n<\/pre>\n<p>The key here is <code>void_t<\/code>. It&#8217;s a template alias that takes any template arguments, and always produces <code>void<\/code>. So what&#8217;s the use of that? Well, it doesn&#8217;t take just <em>any old arguments<\/em>. It can only work with <em>well-formed types<\/em>. So what happens if we give it a type that isn&#8217;t well-formed? Nothing too bad &#8211; because of course, Substitution Failure Is Not An Error.<\/p>\n<p>Look at <code>operator_output_t<\/code>. It uses <code>decltype<\/code> to produce the type of outputting a <code>T<\/code>. If <code>T<\/code> doesn&#8217;t support <code>operator&lt;&lt;<\/code>, this type will be invalid.<\/p>\n<p>Now look at <code>has_operator_output<\/code>. We specialize it using the result of <code>void_t<\/code> on <code>operator_output_t&lt;T&gt;<\/code>. If this is ill-formed (<code>T<\/code> can&#8217;t support <code>operator&lt;&lt;<\/code>) then substitution fails and the unspecialized template, <code>std::false_type<\/code>, is used. But if T supports <code>operator&lt;&lt;<\/code>, the result of <code>void_t<\/code> is well-formed. It&#8217;s still <code>void<\/code>, but <em>it&#8217;s more specialized<\/em> than the default template and so we get <code>std::true_type<\/code>!<\/p>\n<p>That is the magic that <code>void_t<\/code> allows; a whole new frontier of template metaprogramming. (And if we relax the &#8220;because-we-can-be-general&#8221; variadic template, and convert the template aliases, it&#8217;s plain old C++98 specialization! Although it&#8217;s the combo with <code>decltype<\/code> and <code>declval<\/code> that really gives it phenomenal cosmic power.)<\/p>\n<p>I&#8217;m going to set up a template to work on the tag types, so that the default implementation of <code>stringifier<\/code> in <a href=\"https:\/\/www.elbeno.com\/blog\/?p=951\">part 1<\/a> now becomes <code>stringifier_select<\/code> with a tag type that we can specialize on:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T, typename TAG>\r\nstruct stringifier_select;\r\n\r\ntemplate <typename T>\r\nusing stringifier = stringifier_select<T, stringifier_tag<T>>;\r\n\r\ntemplate <typename T, typename TAG>\r\nstruct stringifier_select\r\n{\r\n  explicit stringifier_select(const T&) {}\r\n\r\n  std::ostream& output(std::ostream& s) const\r\n  {\r\n    return s << \"<unknown>\";\r\n  }\r\n};\r\n<\/pre>\n<p>And I can set up type discrimination for outputtable types, and implement their <code>output<\/code> function trivially:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nusing stringifier_tag = std::conditional_t<\r\n  has_operator_output<T>::value,\r\n  is_outputtable_tag,\r\n  void>;\r\n\r\ntemplate <typename T>\r\nstruct stringifier_select<T, is_outputtable_tag>\r\n{\r\n  explicit stringifier_select(const T& 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 T&#038; m_t;\r\n};\r\n<\/pre>\n<p>So, now that we know the <code>void_t<\/code> pattern, it's trivial to use it for detecting any container type; in fact, any type that has <code>begin()<\/code> and <code>end()<\/code>.<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nusing begin_t = decltype(std::declval<T>().begin());\r\n\r\ntemplate <typename T, typename = void>\r\nstruct has_begin : public std::false_type {};\r\n\r\ntemplate <typename T>\r\nstruct has_begin<T, void_t<begin_t<T>>> \r\n  : public std::true_type {};\r\n\r\ntemplate <typename T>\r\nusing end_t = decltype(std::declval<T>().end());\r\n\r\ntemplate <typename T, typename = void>\r\nstruct has_end : public std::false_type {};\r\n\r\ntemplate <typename T>\r\nstruct has_end<T, void_t<end_t<T>>> \r\n  : public std::true_type {};\r\n<\/pre>\n<p>And then we have a very straightforward way to detect a container or other iterable type:<\/p>\n<pre lang=\"cpp\">\r\ntemplate<typename T>\r\nusing is_iterable = typename std::conditional<\r\n  has_begin<T>::value && has_end<T>::value,\r\n  std::true_type, std::false_type>::type;\r\n<\/pre>\n<p>To actually output a container, we will need to output surrounding braces and a comma in between each element. We might want to vary opening\/closing\/separating characters by container type, so I want to allow them to be specialized:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nstruct iterable_opener\r\n{\r\n  constexpr const char* operator()(const T&) const\r\n  { return \"{\"; }\r\n};\r\n\r\ntemplate <typename T>\r\nstruct iterable_closer\r\n{\r\n  constexpr const char* operator()(const T&) const\r\n  { return \"}\"; }\r\n};\r\n\r\ntemplate <typename T>\r\nstruct iterable_separator\r\n{\r\n  constexpr const char* operator()(const T&) const\r\n  { return \",\"; }\r\n};\r\n<\/pre>\n<p>I originally implemented each of these as a straightforward <code>const char*<\/code>, but using functions and passing the container itself allows them to access (for example) size information which might be useful.<\/p>\n<p>Now that we have the customization points in place, we can write the specialization of <code>stringifier<\/code> for containers. There's a minor wrinkle to deal with fenceposting the separators.<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nstruct stringifier_select<T, is_iterable_tag>\r\n{\r\n  explicit stringifier_select(const T& t) : m_t(t) {}\r\n\r\n  std::ostream& output(std::ostream& s) const\r\n  {\r\n    s << iterable_opener<T>()(m_t);\r\n    auto b = m_t.begin();\r\n    auto e = m_t.end();\r\n    if (b != e)\r\n      s << prettyprint(*b);\r\n    std::for_each(++b, e,\r\n                  [&#038;s, this] (auto&#038; e)\r\n                  { s << iterable_separator<T>()(m_t)\r\n                      << prettyprint(e); });\r\n    return s << iterable_closer<T>()(m_t);\r\n  }\r\n  const T& m_t;\r\n};\r\n<\/pre>\n<p>(Notice that it calls <code>prettyprint<\/code> to output each element recursively.) And that's it, we can handle all iterable things. Next, handling <code>pair<\/code> and <code>tuple<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Part 1 Part 2 Part 3 Part 4 Part 5 Postscript We have a basic plan, and the ability to detect concrete types. But how can we detect whether an object supports output with operator&lt;&lt;? For this, there is a recently-discovered amazing trick. Here&#8217;s the code: template using void_t =&#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-958","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\/958","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=958"}],"version-history":[{"count":9,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/958\/revisions"}],"predecessor-version":[{"id":1000,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/958\/revisions\/1000"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=958"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=958"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=958"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}