{"id":964,"date":"2015-02-02T00:01:00","date_gmt":"2015-02-02T08:01:00","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=964"},"modified":"2015-06-30T21:17:27","modified_gmt":"2015-07-01T04:17:27","slug":"how-to-print-anything-in-c-part-3","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=964","title":{"rendered":"How to print anything in C++ (part 3)"},"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&#8217;ve dealt with things that are already outputtable with <code>operator&lt;&lt;<\/code>, and things that are iterable with <code>begin()<\/code> and <code>end()<\/code>. To round out the &#8220;containers&#8221;, we need to deal with <code>pair<\/code> and <code>tuple<\/code>. It&#8217;s simple to print a <code>pair<\/code>:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nstruct stringifier_select<T, is_pair_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 << '(' << prettyprint(m_t.first)\r\n             << ',' << prettyprint(m_t.second) << ')';\r\n  }\r\n\r\n  const T&#038; m_t;\r\n};\r\n<\/pre>\n<p>Printing a <code>tuple<\/code> is a little harder. There is no easy way to iterate through a <code>tuple<\/code>, but that's what we want to do. A <code>tuple<\/code> is designed for compile-time member access where you know either the index (from C++11) or the type (from C++14) of the element you want. So what we need is a compile-time way of iterating through an index. And that's what <code>std::index_sequence<\/code> is for.<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename F, typename...Ts, std::size_t...Is>\r\ninline void for_each_in_tuple(const std::tuple<Ts...>& t,\r\n                              F f,\r\n                              std::index_sequence<Is...>)\r\n{\r\n  (void)(int[]) { 0, (f(std::get<Is>(t), Is), 0)... };\r\n}\r\ntemplate <typename F, typename...Ts>\r\ninline void for_each_in_tuple(const std::tuple<Ts...>& t, F f)\r\n{\r\n  for_each_in_tuple(t, f, std::make_index_sequence<sizeof...(Ts)>());\r\n}\r\n<\/pre>\n<p>This is a handy function to have around. It applies a function to each element of a <code>tuple<\/code>. First (in the second function seen here), we create a <code>std::index_sequence<\/code> equal to the size of the <code>tuple<\/code>. Then (in the top function) we construct an <code>int<\/code> array using uniform initialization. To deal with zero-length <code>tuple<\/code>s, the array has one zero element to begin. After that, each element of the array is our function applied to the thing at the current index and the index itself, sequenced with zero using the comma operator, so that whatever is returned, the array gets a zero and is happy.<\/p>\n<p>I decided to pass both the element and the index to the function to deal with the separator fencepost problem (as with containers). So outputting a <code>tuple<\/code> looks like this:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nstruct stringifier_select<T, is_tuple_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 << '(';\r\n    for_each_in_tuple(m_t,\r\n                      [&#038;s] (auto&#038; e, size_t i)\r\n                      { if (i > 0) s << ',';\r\n                        s << prettyprint(e); });\r\n    return s << ')';\r\n  }\r\n\r\n  const T&#038; m_t;\r\n};\r\n<\/pre>\n<p>Going well so far. Next, I'll look at distinguishing callable things.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Part 1 Part 2 Part 3 Part 4 Part 5 Postscript So far, we&#8217;ve dealt with things that are already outputtable with operator&lt;&lt;, and things that are iterable with begin() and end(). To round out the &#8220;containers&#8221;, we need to deal with pair and tuple. It&#8217;s simple to print a&#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-964","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\/964","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=964"}],"version-history":[{"count":5,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/964\/revisions"}],"predecessor-version":[{"id":999,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/964\/revisions\/999"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=964"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=964"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=964"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}