I have an input iterator that can walk through a file and parse records from it along the way. Each parsed record is stored in the iterator and owned by it (“stashed”).
The records are not lightweight and there are a lot of them, so it would be unfortunate to copy the values. I’d like to be able to move them out of the iterator, so I define dereferencing like so:
Record& operator*() { return this->record; }
This code works:
Record r = std::move(*it); // no copy
Then I wanted to achieve compile-time safety for this iterator using appropriate C++20 concepts, and I’ve added:
static_assert(std::input_iterator<Iterator>);
It fails, because a part of std::input_iterator
– std::indirectly_readable
– requires that const Iterator
is dereferenceable (related question: Why is a simple iterator not readable?). I can’t make my operator*
work on const
, because then it has to return a const reference and move
will actually copy:
const Record& operator*() const { return this->record; }
Record r = std::move(*it); // copy, 'cause can't move const objects
I’ve found that using static_assert(std::input_or_output_iterator)
works with a mutable dereference. It could be ok for static checks, but I find it confusing, because my iterator is not an output_iterator conceptually.
Another related problem is that std::move_iterator
doesn’t work with this mutable dereference operator, because its operator*()
is const, defined as:
reference operator*() const { return ranges::iter_move(__current_); }
where __current_
will be bound to my Iterator, and it will have type const Iterator
in this context, which iter_move wants to dereference and fails, because it doesn’t support immutable dereference (and even if it did by adding const
, it wouldn’t work properly, it would deceptively copy the value instead of moving).
What would be an alternative design to achieve moveability of a stashing iterator, and make move_iterator work?