{"id":1693,"date":"2016-04-07T16:19:55","date_gmt":"2016-04-07T06:19:55","guid":{"rendered":"http:\/\/brnz.org\/hbr\/?p=1693"},"modified":"2016-04-08T11:58:28","modified_gmt":"2016-04-08T01:58:28","slug":"aside-over-engineered-min-c-variadic-templates-constexpr-fold-left","status":"publish","type":"post","link":"https:\/\/brnz.org\/hbr\/?p=1693","title":{"rendered":"Aside: Over-engineered Min() [C++, variadic templates, constexpr, fold left]"},"content":{"rendered":"<p><strong>Q:<\/strong> Given a function <code>constexpr int Min(int a, int b)<\/code>, construct a function\u00a0<code>constexpr int\u00a0Min(Args... args)<\/code> that returns the minimum of all the provided args. Fail to justify your over-engineering.<\/p>\n<p><strong>A:<\/strong>\u00a0Rename <code>Min(int, int)<\/code> as <code>MinImpl(int, int)<\/code>\u00a0or stick it in a namespace. Overloading the function is not only unnecessary, it gets in the way of the implementation.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">constexpr int MinImpl(int a, int b)\r\n{\r\n  return a &lt; b ? a : b;\r\n}<\/pre>\n<p>Implement a <code>constexpr<\/code> fold left function. If we can use it for <code>Min()<\/code>, we should be able to do the same for <code>Max()<\/code>, and other similar functions. Should we be able to find any (#prematuregeneralization).<\/p>\n<pre class=\"brush: cpp; first-line: 6; title: ; notranslate\" title=\"\">template&lt;typename ArgA, typename ArgB, typename Func&gt;\r\nconstexpr auto foldl(Func func, ArgA a, ArgB b)\r\n{\r\n  return func(a, b);\r\n}\r\n\r\ntemplate&lt;typename ArgA, typename ArgB,\r\ntypename Func, typename ...Args&gt;\r\nconstexpr auto foldl(Func func, ArgA a, ArgB b, Args... args)\r\n{\r\n  return foldl(func, func(a, b), args...);\r\n}<\/pre>\n<p>Combine the two.<\/p>\n<pre class=\"brush: cpp; first-line: 19; title: ; notranslate\" title=\"\">template&lt;typename ...Args&gt;\r\nconstexpr auto Min(Args... args)\r\n{\r\n  return foldl(MinImpl, args...);\r\n}<\/pre>\n<p>Add the bare minimum amount of testing for a constexpr function: slap a <code>static_assert()<\/code> on it.<\/p>\n<pre class=\"brush: cpp; first-line: 25; title: ; notranslate\" title=\"\">static_assert(Min(6, 4, 5, 3, 9) == 3), &quot;Nope&quot;);<\/pre>\n<p>I did so with Visual Studio 2015 Update 2. It did not object.<\/p>\n<p><strong>Addendum:<\/strong> Some discussion with <a href=\"https:\/\/twitter.com\/nlguillemot\">@nlguillemot<\/a>\u00a0and\u00a0<a href=\"https:\/\/twitter.com\/DrPizza\">@DrPizza<\/a>\u00a0led to this attempt to do something similar with <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/fold\">a C++17\/C++1z fold-expression<\/a>:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">#include &lt;limits.h&gt;\r\n\r\nconstexpr int MinImpl1(int a, int b) { return a &lt; b ? a : b; }\r\n\r\nconstexpr void MinImpl2(int* m, int a, int b) { *m = a &lt; b ? a : b; }\r\n\r\ntemplate&lt;typename ...Args&gt;\r\nconstexpr int Min(Args... args)\r\n{\r\n  int m = INT_MAX;\r\n  \/\/ a binary expression in an operand of a fold-expression \r\n  \/\/ is not allowed, so this won't compile:\r\n  \/\/((m = MinImpl1(m, args), ...);\r\n\r\n  \/\/ But this does:\r\n  (MinImpl2(\/*out*\/&amp;m, m, args), ...);\r\n  return m;\r\n}\r\n\r\nint main()\r\n{\r\n  static_assert(Min(3,4,5) == 3, &quot;nope&quot;);\r\n}<\/pre>\n<p><a href=\"http:\/\/godbolt.org\/g\/l5701w\">This compiles with a gcc-6 pre-release snapshot.<\/a><\/p>\n<p><strong>Update:<\/strong> <a href=\"https:\/\/godbolt.org\/g\/zkEKWs\">Here&#8217;s a further updated version<\/a>, based on <a href=\"https:\/\/godbolt.org\/g\/3kQQeY\">a refinement<\/a>\u00a0by <a href=\"https:\/\/twitter.com\/dotstdy\/status\/718250945520484353\">@dotstdy<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Q: Given a function constexpr int Min(int a, int b), construct a function\u00a0constexpr int\u00a0Min(Args&#8230; args) that returns the minimum of all the provided args. Fail to justify your over-engineering. A:\u00a0Rename Min(int, int) as MinImpl(int, int)\u00a0or stick it in a namespace. Overloading the function is not only unnecessary, it gets in the way of the implementation. &hellip; <a href=\"https:\/\/brnz.org\/hbr\/?p=1693\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Aside: Over-engineered Min() [C++, variadic templates, constexpr, fold left]&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5,26],"tags":[],"_links":{"self":[{"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/posts\/1693"}],"collection":[{"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1693"}],"version-history":[{"count":23,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/posts\/1693\/revisions"}],"predecessor-version":[{"id":1716,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=\/wp\/v2\/posts\/1693\/revisions\/1716"}],"wp:attachment":[{"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1693"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1693"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brnz.org\/hbr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1693"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}