{"id":110820,"date":"2025-01-30T07:00:00","date_gmt":"2025-01-30T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110820"},"modified":"2025-01-31T08:24:27","modified_gmt":"2025-01-31T16:24:27","slug":"20250130-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250130-00\/?p=110820","title":{"rendered":"Creating a generic insertion iterator, part 1"},"content":{"rendered":"<p>Last time, we <a title=\"How do I create an inserter iterator that does unhinted insertion into an associative container like std::map?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250129-00\/?p=110817\"> created an inserter iterator that does unhinted insertion<\/a>. We noticed that most of the iterator is just boilerplate, so let&#8217;s generalize it into a version that is all-boilerplate.<\/p>\n<pre>\/\/ Do not use: See discussion\r\ntemplate&lt;typename Lambda&gt;\r\nstruct generic_output_iterator\r\n{\r\n    using iterator_category = std::output_iterator_tag;\r\n    using value_type = void;\r\n    using pointer = void;\r\n    using reference = void;\r\n    using difference_type = void;\r\n\r\n    generic_output_iterator(Lambda&amp;&amp; lambda) :\r\n        insert(std::forward&lt;Lambda&gt;(lambda)) {}\r\n\r\n    generic_output_iterator&amp; operator*() noexcept\r\n        { return *this; }\r\n    generic_output_iterator&amp; operator++() noexcept\r\n        { return *this; }\r\n    generic_output_iterator&amp; operator++(int) noexcept\r\n        { return *this; }\r\n\r\n    template&lt;typename Value&gt;\r\n    generic_output_iterator&amp; operator=(\r\n        Value&amp;&amp; value)\r\n    {\r\n        insert(std::forward&lt;Value&gt;(value));\r\n        return *this;\r\n    }\r\n\r\nprotected:\r\n    std::decay_t&lt;Lambda&gt; insert;\r\n\r\n};\r\n\r\ntemplate&lt;typename Lambda&gt;\r\ngeneric_output_iterator&lt;Lambda&gt;\r\ngeneric_output_inserter(Lambda&amp;&amp; lambda) {\r\n    return generic_output_iterator&lt;Lambda&gt;(\r\n        std::forward&lt;Lambda&gt;(lambda));\r\n}\r\n\r\ntemplate&lt;typename Lambda&gt;\r\ngeneric_output_iterator(Lambda&amp;&amp;) -&gt;\r\n    generic_output_iterator&lt;Lambda&gt;;\r\n<\/pre>\n<p>For convenience, I provided both a deduction guide and a maker function, so you can use whichever version appeals to you.\u00b9<\/p>\n<p>The generic output iterator uses the lambda to process each insertion. You can make the lambda do anything you like. For example:<\/p>\n<pre>auto sample(std::vector&lt;int&gt;&amp; v)\r\n{\r\n    std::map&lt;int&gt; m;\r\n    std::copy(v.begin(), v.end(),\r\n        generic_output_iterator(\r\n            [&amp;m, hint = m.begin()](int v) mutable {\r\n            hint = m.insert(hint, { v, 0 });\r\n        }));\r\n}\r\n<\/pre>\n<p>In this example, we take a vector of what we expect to be a mostly-sorted sequence of integers and use them as keys in a newly-created map, where the associated integer is initialized to zero. We take advantage of the mostly-sorted-ness by using the location of the previously-inserted item as the hint for the next item.<\/p>\n<p>Too bad this is not a valid iterator!<\/p>\n<p>Among the requirements for iterators is that they be default-constructible and assignable, and ours is neither because capturing lambdas are neither default-constructible nor assignable. (Capturing lambdas can be copy-constructible and move-constructible, but they are never default-constructible or assignable.)<\/p>\n<p>We&#8217;ll try to fix this problem next time.<\/p>\n<p>\u00b9 The C++ standard library has a lot of maker functions because they predate class template argument deduction (CTAD) and deduction guides.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We provide the boilerplate; you provide the smarts.<\/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-110820","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>We provide the boilerplate; you provide the smarts.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110820","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=110820"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110820\/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=110820"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110820"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110820"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}