Creating a generic insertion iterator, part 1
We provide the boilerplate; you provide the smarts. The post Creating a generic insertion iterator, part 1 appeared first on The Old New Thing.
Last time, we created an inserter iterator that does unhinted insertion. We noticed that most of the iterator is just boilerplate, so let’s generalize it into a version that is all-boilerplate.
// Do not use: See discussion templatestruct generic_output_iterator { using iterator_category = std::output_iterator_tag; using value_type = void; using pointer = void; using reference = void; using difference_type = void; generic_output_iterator(Lambda&& lambda) : insert(std::forward (lambda)) {} generic_output_iterator& operator*() noexcept { return *this; } generic_output_iterator& operator++() noexcept { return *this; } generic_output_iterator& operator++(int) noexcept { return *this; } template generic_output_iterator& operator=( Value&& value) { insert(std::forward (value)); return *this; } protected: std::decay_t insert; }; template generic_output_iterator generic_output_inserter(Lambda&& lambda) { return generic_output_iterator ( std::forward (lambda)); } template generic_output_iterator(Lambda&&) -> generic_output_iterator ;
For convenience, I provided both a deduction guide and a maker function, so you can use whichever version appeals to you.¹
The generic output iterator uses the lambda to process each insertion. You can make the lambda do anything you like. For example:
auto sample(std::vector& v) { std::map m; std::copy(v.begin(), v.end(), generic_output_iterator( [&m, hint = m.begin()](int v) mutable { hint = m.insert(hint, { v, 0 }); })); }
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.
Too bad this is not a valid iterator!
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.)
We’ll try to fix this problem next time.
¹ The C++ standard library has a lot of maker functions because they predate class template argument deduction (CTAD) and deduction guides.
The post Creating a generic insertion iterator, part 1 appeared first on The Old New Thing.