I'm implementing an iterator that iterates over the results of a generator function rather than over a data structure in memory such as a vector or map.
Reading through the final working draft for C++17 §27.2.3, the return type of the dereference operator for an input iterator (and by extension, most other iterators) a forward iterator is required to be a reference. This is fine for items that exist in the data structure the iterator is iterating over. However, because I'm not using a data structure and am calculating each item when the dereference operator is called, I don't have a valid reference to return; the calculated item is destroyed when the operator returns. To work around this, I am storing the result of the calculation in the iterator itself and returning a reference to the stored result. This works fine for my use case, but has issues of its own when used with arbitrary user-defined types.
I can understand iterators being allowed to return a reference, but why would this be a requirement for non-mutating iterators? Did the writers of the standard not consider generators and on-the-fly transformations to be valid use cases for iterators? Would returning a value instead of a const reference cause any actual harm?
[edit]: I'm asking more out of curiosity about why the standard is written the way it is, since I already have a perfectly good workaround.
Dereferencing an input iterator is not required to yield a glvalue (that is, return a reference). The input iterator requirements say that the return type when dereferencing must be "reference
, convertible to T
" but nowhere does it say that reference
must be a reference type.
However, dereferencing a forward iterator is required to yield a glvalue:
if
X
is a mutable iterator,reference
is a reference toT
; ifX
is a constant iterator,reference
is a reference toconst T
,
So go ahead and write your iterator that generates elements on the fly, but it can only be an input iterator, not a forward iterator. For many algorithms this is sufficient (e.g., std::for_each
and std::all_of
).