There are various STL algorithms that rely on an output iterator to store the result of the algorithm.
For example, std::set_intersection
will store all the common elements between two sorted ranges in an Output iterator that is then post incremented per element outputted.
Sometimes, I am not interested in the actual elements but only the number of output elements. In such cases it is a waste of memory and performance to copy the elements. Is there an iterator adapter that I can use to count and avoid the copy of the elements? If not can you suggest a generic implementation of such an adapter?
Boost's Function Output Iterator can do what you want:
std::size_t count = 0u;
int arr[]{0, 1, 2, 3};
std::copy(std::begin(arr), std::end(arr),
boost::make_function_output_iterator([&](auto const&) { ++count; }));
assert(count == 4u);
The only issue is that you have to declare the count variable outside the iterator, because there's no way to extract the stored function object from a boost::function_output_iterator
(and also no way to extract the closure values from a lambda, even if you got past that hurdle). If you want to be able to write one-liners, you'll have to write the iterator class yourself, but it's not a huge amount of code; for example:
class counting_output_iterator {
public:
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
std::size_t value = 0u;
struct output_proxy {
output_proxy(std::size_t& value) : m_value(value) { }
template<class T> output_proxy& operator=(T const&) {
++m_value;
return *this;
}
std::size_t& m_value;
};
output_proxy operator*() { return output_proxy(value); }
counting_output_iterator& operator++() { return *this; }
counting_output_iterator& operator++(int) { return *this; }
};
Usage:
int arr[]{0, 1, 2, 3};
auto const count = std::copy(std::begin(arr), std::end(arr),
counting_output_iterator{}).value;
assert(count == 4u);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With