{"id":5998,"date":"2020-10-11T08:57:08","date_gmt":"2020-10-11T08:57:08","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/extend-std-format-in-c-20-for-user-defined-types\/"},"modified":"2023-06-26T09:42:13","modified_gmt":"2023-06-26T09:42:13","slug":"extend-std-format-in-c-20-for-user-defined-types","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/extend-std-format-in-c-20-for-user-defined-types\/","title":{"rendered":"C++20: Extend std::format for User-Defined Types"},"content":{"rendered":"<p>Peter Gottschling presented in his last post &#8220;<a href=\"https:\/\/bit.ly\/stdFormat\">std::format in C++20<\/a>&#8221; the basics of the new formatting library in C++20. In today&#8217;s post, Peter writes about the formatting of user-defined types.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5945\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/07\/TimelineCpp20CoreLanguage.png\" alt=\"TimelineCpp20CoreLanguage\" width=\"650\" height=\"267\" style=\"display: block; margin-left: auto; margin-right: auto;\" \/><\/p>\n<p>Our first example of template specialization is customizing the new format library introduced to support user types.<\/p>\n<h2>Formatting User-Defined Types<\/h2>\n<p>For example, we choose the<code> dmc::vector<\/code> (<code>dmc<\/code> is the namespace from the book &#8220;Discovering Modern C++&#8221; by the author) class for which we like to specify the formatting of the single values. In addition, we want to replace the enclosing brackets with curly braces when the format string contains the letter <code>'c'<\/code>. To this end, we have to specialize the class <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/format\/formatter\"><code>std::formatter <\/code><\/a>(or<code> fmt::formatter<\/code> for the prototype library <code><a href=\"https:\/\/github.com\/fmtlib\/fmt\">fmt<\/a><\/code>). Our specialization shall contain the methods <code>parse<\/code> and <code>format<\/code>.<\/p>\n<p>Let&#8217;s start with the former:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Value<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> formatter<span style=\"color: #555555;\">&lt;<\/span>dmc<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>Value<span style=\"color: #555555;\">&gt;&gt;<\/span>\r\n{\r\n    constexpr <span style=\"color: #006699; font-weight: bold;\">auto<\/span> parse(format_parse_context<span style=\"color: #555555;\">&amp;<\/span> ctx)\r\n    {\r\n        value_format<span style=\"color: #555555;\">=<\/span> <span style=\"color: #cc3300;\">\"{:\"<\/span>;        \r\n        <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> it<span style=\"color: #555555;\">=<\/span> begin(ctx); it <span style=\"color: #555555;\">!=<\/span> end(ctx); <span style=\"color: #555555;\">++<\/span>it) {\r\n            <span style=\"color: #007788; font-weight: bold;\">char<\/span> c<span style=\"color: #555555;\">=<\/span> <span style=\"color: #555555;\">*<\/span>it;\r\n            <span style=\"color: #006699; font-weight: bold;\">if<\/span> (c <span style=\"color: #555555;\">==<\/span> <span style=\"color: #cc3300;\">'c'<\/span>)\r\n                curly<span style=\"color: #555555;\">=<\/span> <span style=\"color: #336666;\">true<\/span>;\r\n            <span style=\"color: #006699; font-weight: bold;\">else<\/span>\r\n                value_format<span style=\"color: #555555;\">+=<\/span> c;\r\n            <span style=\"color: #006699; font-weight: bold;\">if<\/span> (c <span style=\"color: #555555;\">==<\/span> <span style=\"color: #cc3300;\">'}'<\/span>)\r\n                <span style=\"color: #006699; font-weight: bold;\">return<\/span> it;\r\n        }\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> end(ctx);\r\n    }\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">bool<\/span>        curly{<span style=\"color: #336666;\">false<\/span>};\r\n    std<span style=\"color: #555555;\">::<\/span>string value_format;\r\n};\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>As an argument, the parse context is given whose <code>begin<\/code> iterator points to the first character of the format specification, i.e.~the first character after the colon and, in its absence, the first character after the opening brace. We copy the format specification almost identically to our local <code>value_format,<\/code> only our unique character <code>'c'<\/code> is skipped. For simplicity, we assume that the format doesn&#8217;t contain any opening or closing brace, so the next closing brace terminates our format string. Finally, we return the iterator pointing to the closing brace or the end iterator.<\/p>\n<p class=\"PreformattedText\"><span lang=\"DE\" style=\"color: black;\">With this information, we can output our <\/span><span lang=\"DE\" style=\"color: maroon;\"><\/span><span lang=\"DE\" style=\"color: black;\"><code>vector<\/code> in the method <\/span><span lang=\"DE\" style=\"color: maroon;\"><\/span><span lang=\"DE\" style=\"color: black;\"><code>format<\/code>:<\/span><span lang=\"DE\"><\/span><\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Value<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> formatter<span style=\"color: #555555;\">&lt;<\/span>dmc<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>Value<span style=\"color: #555555;\">&gt;&gt;<\/span>\r\n{\r\n    <span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> FormatContext<span style=\"color: #555555;\">&gt;<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> format(<span style=\"color: #006699; font-weight: bold;\">const<\/span> dmc<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>Value<span style=\"color: #555555;\">&gt;&amp;<\/span> v, FormatContext<span style=\"color: #555555;\">&amp;<\/span> ctx)\r\n    {\r\n        <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;&amp;<\/span> out<span style=\"color: #555555;\">=<\/span> ctx.out();\r\n        format_to(out, curly <span style=\"color: #555555;\">?<\/span> <span style=\"color: #cc3300;\">\"{{\"<\/span> <span style=\"color: #555555;\">:<\/span> <span style=\"color: #cc3300;\">\"[\"<\/span>);\r\n        <span style=\"color: #006699; font-weight: bold;\">if<\/span> (v.size() <span style=\"color: #555555;\">&gt;<\/span> <span style=\"color: #ff6600;\">0<\/span>)\r\n            format_to(out, value_format, v[<span style=\"color: #ff6600;\">0<\/span>]);\r\n        <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #007788; font-weight: bold;\">int<\/span> i<span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span>; i <span style=\"color: #555555;\">&lt;<\/span> v.size(); <span style=\"color: #555555;\">++<\/span>i)\r\n            format_to(out, <span style=\"color: #cc3300;\">\", \"<\/span> <span style=\"color: #555555;\">+<\/span> value_format, v[i]);\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc00ff;\">format_to<\/span>(out, curly <span style=\"color: #555555;\">?<\/span> <span style=\"color: #cc3300;\">\"}}\"<\/span> <span style=\"color: #555555;\">:<\/span> <span style=\"color: #cc3300;\">\"]\"<\/span>);\r\n    }\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n};\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>First, we take a reference to the output buffer. Then we write the opening brace or bracket to it. Since braces have a special meaning in the <code>format<\/code> library, we need an escape sequence of double braces. The remaining output is equivalent to the <code>ostream<\/code> output. Finally, we return the output buffer.<\/p>\n<p class=\"PreformattedText\"><span lang=\"DE\" style=\"color: black;\">Now we can try various formats:<\/span><\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">dmc<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">double<\/span><span style=\"color: #555555;\">&gt;<\/span> v{<span style=\"color: #ff6600;\">1.394<\/span>, <span style=\"color: #ff6600;\">1e9<\/span>, <span style=\"color: #ff6600;\">1.0<\/span><span style=\"color: #555555;\">\/<\/span><span style=\"color: #ff6600;\">3.0<\/span>, <span style=\"color: #ff6600;\">1e-20<\/span>};\r\nprint(<span style=\"color: #cc3300;\">\"v with empty format = {:}.<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, v);\r\nprint(<span style=\"color: #cc3300;\">\"v with f = {:f}.<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, v);\r\nprint(<span style=\"color: #cc3300;\">\"v curly with f = {:fc}.<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, v);\r\nprint(<span style=\"color: #cc3300;\">\"v width 9, 4 digits = {:9.4f}.<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, v);\r\nprint(<span style=\"color: #cc3300;\">\"v scient. = {:ec}.<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, v);\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>and see the outputs:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">v with empty format = [1.394, 1000000000.0, 0.3333333333333333, 1e-20].\r\nv with f = [1.394000, 1000000000.000000, 0.333333, 0.000000].\r\nv curly with f = {1.394000, 1000000000.000000, 0.333333, 0.000000}.\r\nv width 9, 4 digits = [   1.3940, 1000000000.0000,    0.3333,    0.0000].\r\nv scient. = {1.394000e+00, 1.000000e+09, 3.333333e-01, 1.000000e-20}.\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Altogether, since the new formatting is:<\/p>\n<ul>\n<li><strong>Compact<\/strong>: demonstrated in the examples above<\/li>\n<li><strong>Adaptable:<\/strong> to various output orders<\/li>\n<li><strong>Type-safe<\/strong>: an exception is thrown when an argument doesn&#8217;t match<\/li>\n<li><strong>Extensible<\/strong>: can be extended to user-defined types<\/li>\n<\/ul>\n<p>For those reasons, it is superior to the preceding techniques, and we strongly advise using it as soon as sufficient compiler support is available.<\/p>\n<p>Thanks once more to Peter Gottschling for providing a compact introduction to <code>std::format<\/code>. Let me add a few words to complete his introduction to the formatting library.<\/p>\n<\/p>\n<h2>Try It Out<\/h2>\n<p>As Peter mentioned, the GitHub-hosted <code><a href=\"https:\/\/github.com\/fmtlib\/fmt\">fmt <\/a><\/code>library is a prototype for the new formatting library in C++20. The project&#8217;s front page includes a few straightforward examples and performance numbers. These examples include a direct link to the compiler explorer for executing the example.<\/p>\n<p>Thanks to the new formatting library, you can display time durations of the<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/chrono\">&nbsp;<code>chrono<\/code><\/a> library:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #009999;\">#include &lt;fmt\/chrono.h&gt;<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n  <span style=\"color: #006699; font-weight: bold;\">using<\/span> <span style=\"color: #006699; font-weight: bold;\">namespace<\/span> std<span style=\"color: #555555;\">::<\/span>literals<span style=\"color: #555555;\">::<\/span>chrono_literals;\r\n  fmt<span style=\"color: #555555;\">::<\/span>print(<span style=\"color: #cc3300;\">\"Default format: {} {}<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, <span style=\"color: #ff6600;\">42<\/span>s, <span style=\"color: #ff6600;\">100<\/span>ms);\r\n  fmt<span style=\"color: #555555;\">::<\/span>print(<span style=\"color: #cc3300;\">\"strftime-like format: {:%H:%M:%S}<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, <span style=\"color: #ff6600;\">3<\/span>h <span style=\"color: #555555;\">+<\/span> <span style=\"color: #ff6600;\">15<\/span>min <span style=\"color: #555555;\">+<\/span> <span style=\"color: #ff6600;\">30<\/span>s);\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Executing the program on the compiler explorer gives you the following output:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5997\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/10\/formatChrono.PNG\" alt=\"formatChrono\" width=\"300\" height=\"55\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/10\/formatChrono.PNG 402w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/10\/formatChrono-300x55.png 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<h2>Porting to C++20<\/h2>\n<p>Porting the previous program from <code>fmt<\/code>&nbsp;the C++20 format library is a piece of cake. You have to use the C++ standard header <code>chrono<\/code> and <code>iostream<\/code>. Additionally, replace the call <code>fmt::print<\/code> with the function <code>std::format <\/code>and push the result to <code>std::cout<\/code>. <code>std::format<\/code> returns a string according to the given format string and an optional local.<\/p>\n<p>&nbsp;<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ formatChrono.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;chrono&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n  <span style=\"color: #006699; font-weight: bold;\">using<\/span> <span style=\"color: #006699; font-weight: bold;\">namespace<\/span> std<span style=\"color: #555555;\">::<\/span>literals<span style=\"color: #555555;\">::<\/span>chrono_literals;\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>format(<span style=\"color: #cc3300;\">\"Default format: {} {}<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, <span style=\"color: #ff6600;\">42<\/span>s, <span style=\"color: #ff6600;\">100<\/span>ms) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>;\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>format(<span style=\"color: #cc3300;\">\"strftime-like format: {:%H:%M:%S}<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>, <span style=\"color: #ff6600;\">3<\/span>h <span style=\"color: #555555;\">+<\/span> <span style=\"color: #ff6600;\">15<\/span>min <span style=\"color: #555555;\">+<\/span> <span style=\"color: #ff6600;\">30<\/span>s) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>;\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>In my <a href=\"https:\/\/www.modernescpp.com\/index.php\/more-and-more-utilities-in-c-20\">next post<\/a>, I will continue with the convenience functions. With C++20, you can calculate the midpoint of two values, check if a <code>std::string<\/code> start or ends with a substring, and create callables with<code> std::bind_front<\/code>.<\/p>\n<p>&nbsp;<\/p>\n<\/p>\n<div id=\"simple-translate\">&nbsp;<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Peter Gottschling presented in his last post &#8220;std::format in C++20&#8221; the basics of the new formatting library in C++20. In today&#8217;s post, Peter writes about the formatting of user-defined types.<\/p>\n","protected":false},"author":21,"featured_media":5945,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[454],"class_list":["post-5998","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-format"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5998","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=5998"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5998\/revisions"}],"predecessor-version":[{"id":6726,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5998\/revisions\/6726"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5945"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5998"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5998"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5998"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}