{"id":103498,"date":"2020-02-28T07:00:00","date_gmt":"2020-02-28T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103498"},"modified":"2020-02-28T10:15:57","modified_gmt":"2020-02-28T18:15:57","slug":"20200228-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200228-00\/?p=103498","title":{"rendered":"Should there be a standard C++ pattern for this? transform_to"},"content":{"rendered":"<p>I&#8217;ve got one type of collection and I want to apply a function to each member of the collection, thereby producing a new collection.<\/p>\n<p>Surely there&#8217;s a standard pattern for this?<\/p>\n<p>In JavaScript, it&#8217;s called <code>map<\/code>:<\/p>\n<pre>function getOldValues()\r\n{\r\n    return [\"a\", \"b\", \"c\", \"d\"];\r\n}\r\n\r\nvar newValues = getOldValues().map(v =&gt; v.charCodeAt(0));\r\n\/\/ result: [97, 98, 99, 100]\r\n<\/pre>\n<p>In C#, it&#8217;s <code>Select<\/code>.<\/p>\n<pre>string[] GetOldValues() =&gt; new[] { \"a\", \"b\", \"c\", \"d\" };\r\n\r\nvar newValues = GetOldValues().Select(v =&gt; (int)v[0]).ToArray();\r\n\/\/ result: int[] { 97, 98, 99, 100 };\r\n<\/pre>\n<p>In C++, it&#8217;s, um, this clumsy <code>std::transform<\/code>.<\/p>\n<pre>std::vector&lt;std::string&gt; GetOldValues()\r\n{\r\n   return { \"a\", \"b\", \"c\", \"d\" };\r\n}\r\n\r\nauto oldValues = GetOldValues();\r\nstd::vector&lt;int&gt; newValues;\r\nnewValues.reserve(oldValues.size());\r\nstd::transform(oldValues.begin(), oldValues.end(),\r\n    std::back_inserter(newValues),\r\n    [](auto&amp;&amp; v) { return v[0]; });\r\n<\/pre>\n<p>It&#8217;s clumsy because you need to give a name to the thing being transformed, because you need to call both <code>begin<\/code> and <code>end<\/code> on it. But giving it a name extends its lifetime, so you end up carrying this <code>oldValues<\/code> vector around for no reason.\u00b9<\/p>\n<p>It&#8217;s clumsy because you have to construct an empty <code>newValues<\/code> and then fill it in.<\/p>\n<p>Would be nice if there were some helper function like<\/p>\n<pre>template&lt;typename T, typename U, typename TLambda&gt;\r\nT transform_to(U&amp;&amp; u, TLambda&amp;&amp; lambda)\r\n{\r\n  T result;\r\n  if constexpr (has_size_v&lt;U&gt; &amp;&amp; has_reserve_v&lt;T&gt;)\r\n  {\r\n    result.reserve(u.size());\r\n  }\r\n  std::transform(u.begin(), u.end(), std::back_inserter(result),\r\n                 std::forward&lt;TLambda&gt;(lambda));\r\n  return result;\r\n}\r\n\r\nauto newValues = std::transform_to&lt;std::vector&lt;int&gt;&gt;(\r\n    GetOldValues(), [](auto&amp;&amp; v) { return v[0]; });\r\n<\/pre>\n<p>Maybe one exists and I&#8217;m missing it? Help me out here.<\/p>\n<p>\u00b9 You can avoid extending the lifetime beyond the transform by pushing it into a lambda:<\/p>\n<pre>auto newValues = [&amp;]()\r\n{\r\n    auto oldValues = GetOldValues();\r\n    std::vector&lt;int&gt; newValues;\r\n    newValues.reserve(oldValues.size());\r\n    std::transform(oldValues.begin(), oldValues.end(),\r\n        std::back_inserter(newValues),\r\n        [](auto&amp;&amp; v) { return v[0]; });\r\n    return newValues;\r\n}();\r\n<\/pre>\n<p>but that&#8217;s basically just taking the <code>transform_to<\/code> function and inlining it as a lambda.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Or maybe you should expect to write it out the slow way.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103498","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Or maybe you should expect to write it out the slow way.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103498","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103498"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103498\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103498"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103498"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103498"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}