Why does std::fill use ForwardIterator, not OutputIterator? - c++

(This question has the same "question template" as Why does std::max_element require a ForwardIterator? but the answer has to be different, because std::fill doesn't return an iterator into the output sequence.)
std::fill is defined to work only when the output range is given by a pair of ForwardIterators. However, the superficially similar std::fill_n works fine with OutputIterator.
Surely the algorithm is simply
template<class OutIt, class T>
void fill(OutIt first, OutIt last, T value)
{
while (first != last) {
*first = value;
++first;
}
}
What about this algorithm requires ForwardIterator? What am I missing?

Output iterators are not comparable. The == and != operators are not defined for output iterators.
You need a forward iterator, because it
satisfies the requirements of an input iterator
which supports EqualityComparable.
With output iterators, std::fill cannot compare first with last:
while (first != last) {
Not supported, for output iterators.
std::fill_n avoids this comparison, it just uses the counter to write to the iterator, so all it needs is an output iterator.

There is no notion of "range" for OutputIterator. Thus you must provide a repetition count. With ForwardIterator you can work over a range of elements.
Those are semantically different things. fill_n is for adding some elements starting from a supplied iterator. fill is for changing a range of elements.
Take inserters (e.g. a back_inserter) for an example. You can insert more elements than there is in the container, so last doesn't even make sense.
OutputIterator gives you a place where you can throw in an object. ForwardIterator objects must exists.
From cppreference:
The only valid use of operator* with an output iterator is on the left of an assignment: operator* may return a proxy object, which defines a member operator= (which may be a template)
This means you basically cannot read from it, which is in the contrast to the ForwardIterator:
A ForwardIterator is an Iterator that can read data from the pointed-to element.

Related

Does `std::find()` short circuit?

Consider I had an std::vector such that its contents were std::strings and {"a","b","c"}. If I were to perform std::find() looking for "a", would it stop once it iterated over "a" (ie. short-circuit) or continue to the end?
std::vector<std::string> vec;
vec.insert(vec.begin(), "a");
vec.insert(vec.begin(), "b");
vec.insert(vec.begin(), "c");
Which is faster?
std::find(vec.begin(), vec.end(), "a");
std::find(vec.begin(), vec.end(), "c");
See the possible implimenation of std::find
template<class InputIt, class T>
constexpr InputIt find(InputIt first, InputIt last, const T& value)
{
for (; first != last; ++first) {
if (*first == value) { // if the condition met
return first; // ---> here returns the iterator
}
}
return last;
}
It will stop iterating, once it finds the match.
Based on description here, yes it does.
Returns the first element in the range [first, last) that satisfies
specific criteria.
Complexity: At most last - first applications of the predicate
And by taking a look at its possible implementations it is stated that std::find uses short circuit
The C++17 standard draft defines the behavior of std::find in [alg.find] (only part relevant to overload used in question cited):
template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last,
const T& value);
[...]
Returns: The first iterator i in the range [first, last) for which the following corresponding conditions hold: *i == value, [...]. Returns last if no such iterator is found.
Complexity: At most last - first applications of the corresponding predicate.
Previous standard versions, including C++03, contain basically the same wording.
Nothing in this guarantees that the elements are searched in any specific order at all or that std::find must stop testing the predicate once it found a match.
However, since the function must return the first iterator in the range satisfying the condition, it makes no sense to test out-of-order, because if a match was found, all previous iterators would need to be tested for an earlier match anyway.
Once a match is found it is also pointless to continue applying the predicate and the standard only requires the predicate to be applied "at most" as often as there are elements in the range.
Therefore any reasonable sequential implementation of std::find will search the iterator range in-order and return when a match is found. If an implementation did not do that, users would complain about it as soon as they noticed. Standard library implementors want their code to be fast where possible and they have no benefit letting their code do more work than necessary.
I suppose though that an implementation could make use of parallelization if it knows that this will not cause data races for the given types and in that case it might happen that the search examines iterators beyond the first match. Whether something like this is implemented in any standard library for the non-parallel std::find overload from the question, I don't know.

Why std::next does not accept InputIterator?

ISO C++11 24.3:
template <class InputIterator, class Distance>
void advance(InputIterator& i, Distance n);
// ...
template <class ForwardIterator>
ForwardIterator next
(
ForwardIterator x,
typename std::iterator_traits<ForwardIterator>::difference_type n = 1
);
Why std::next does not accept InputIterators?
One of legal use cases I am thinking about is:
first = find(next(first, x), last, 11); // ...
I have found appropriate DR:
next/prev return an incremented iterator without changing the value of the original iterator. However, even this may invalidate an InputIterator. A ForwardIterator is required to guarantee the 'multipass' property.
But I don't understand how multipass/invalidation is related to that. Using same multipass/invalidation reasoning, we can even ban std::find for InputIterators:
template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value);
There is nothing special about std::next in compare to std::find or std::vector::insert(pos, first, last) which have perfectly legal use cases for InputIterators
Moreover std::next(it, n) can be used in generic code, which operates not only on InputIterators.
In effect, input iterators cannot be usefully copied, because once an input iterator is incremented, any copy left lying around is invalidated.
std::next takes an iterator and returns another iterator which has been advanced n times. You can't do that with an input iterator without invalidating the original iterator, which makes std::next pointless. By constrast, std::advance advances the specified iterator n times, which is fine with an input iterator.
std::next is the iterator generalization of operator+(T*, size_t). std::advance is the iterator generalization of operator+=(T*&, size_t). It may well be that std::advance, like operator+=, should return a reference instead of void.
It's true that there is a similar issue with std::find (and related functions); they, too, will invalidate any copy of the specified input iterators. But it is quite possible that the committee found that issue less serious.

STL fill and forward iterator

According to most C++ references, for instance cplusplus.com, forward iterators are not required to be assignable (I mean, deferenced to an lvalue). However, for several STL algorithms that need to write values, for instance std::fill (also std::generate etc.), the specification uses forward iterator:
template <class ForwardIterator, class T>
void fill (ForwardIterator first, ForwardIterator last, const T& val);
while the equivalent behavior requires lvalue dereference:
template <class ForwardIterator, class T>
void fill (ForwardIterator first, ForwardIterator last, const T& val)
{
while (first != last) {
*first = val;
++first;
}
}
So, it is actually using a mutable forward iterator with a single pass.
Now the questions are:
(1) Why not make it clear that the forward iterators used in these cases are mutable?
(2) Update: I found the following question to be stupid: I temporarily forgot that output iterators do not need to support equality comparison. The above question remains, anyway.
Why use forward iterators instead of output iterators for std::fill, std::generate etc. while they do not actually need multiple passes? (std::copy only needs output iterators, for instance. What's the rationale?)
From the signature
template <class ForwardIterator, class T>
void fill (ForwardIterator first, ForwardIterator last, const T& val);
you cannot infer that ForwardIterator is an iterator described in forward iterator. However, if you read the parameter description, you will find that first and last must be
Forward Iterators to the initial and final positions in a sequence of elements that support being assigned a value of type T.
(emphasis by me). So a forward iterator that fulfills nothing more than what is required of a forward iterator is not a valid argument.
It doesn't seem terribly strange to me, given that the specification for fill is that the (dereferenced) iterator be assignable from T. An output iterator won't suffice because it's not comparable to determine the range end, so a forward_iterator with requirements was chosen.
You'll note that fill_n does use output iterators because no iterator comparison is needed to determine the end of the sequence to fill.

What's the difference between std::advance and std::next?

Is there more beyond advance takes negative numbers?
std::advance
modifies its argument
returns nothing
works on input iterators or better (or bi-directional iterators if a negative distance is given)
std::next
leaves its argument unmodified
returns a copy of the argument, advanced by the specified amount
works on forward iterators or better (or bi-directional iterators if a negative distance is given))
Perhaps the biggest practical difference is that std::next() is only available from C++11.
std::next() will advance by one by default, whereas std::advance() requires a distance.
And then there are the return values:
std::advance(): (none) (the iterator passed in is modified)
std::next(): The n th successor.
std::next() takes negative numbers just like std::advance, and in that case requires that the iterator must be bidirectional. std::prev() would be more readable when the intent is specifically to move backwards.
std::advance
The function advance() increments the position of an iterator passed as the argument. Thus, the function lets the iterator step forward (or backward) more than one element:
#include <iterator>
void advance (InputIterator& pos, Dist n)
Lets the input iterator pos step n elements forward (or backward).
For bidirectional and random-access iterators, n may be negative to step backward.
Dist is a template type. Normally, it must be an integral type because operations such as <, ++, --, and comparisons with 0 are
called.
Note that advance() does not check whether it crosses the end() of a sequence (it can’t check because iterators in general do not know the
containers on which they operate). Thus, calling this function might
result in undefined behavior because calling operator ++ for the end
of a sequence is not defined.
std::next(and std::prev new in C++11)
#include <iterator>
ForwardIterator next (ForwardIterator pos)
ForwardIterator next (ForwardIterator pos, Dist n)
Yields the position the forward iterator pos would have if moved forward 1 or n positions.
For bidirectional and random-access iterators, n may be negative to yield previous ositions.
Dist is type std::iterator_traits::difference_type.
Calls advance(pos,n) for an internal temporary object.
Note that next() does not check whether it crosses the end() of a sequence. Thus, it is up to the caller to ensure that the result is
valid.
cite from The C++ Standard Library Second Edition
They're pretty much the same, except that std::next returns a copy and std::advance modifies its argument. Note that the standard requires std::next to behave like std::advance:
24.4.4 Iterator operations [iterator.operations]
template <class InputIterator, class Distance>
void advance(InputIterator& i [remark: reference], Distance n);
2. Requires: n shall be negative only for bidirectional and random access iterators
3. Effects: Increments (or decrements for negative n) iterator reference i by n.
[...]
template <class ForwardIterator>
ForwardIterator next(ForwardIterator x, [remark: copy]
typename std::iterator_traits<ForwardIterator>::difference_type n = 1);
6. Effects: Equivalent to advance(x, n); return x;
Note that both actually support negative values if the iterator is an input iterator. Also note that std::next requires the iterator to meet the conditions of an ForwardIterator, while std::advance only needs an Input Iterator (if you don't use negative distances).

Traversing through a set from a particular index to a particular index

I have an iterator. Say I need to traverse the set not from the beginning but from some particular point. Also it is quite difficult for me to get the values stored in the sets as they are pointers. So how to i modify my code to traverse through my sets from a point that is not the begining. ?
Here is the code:
for(iter=make.at(level).begin();iter!=make.at(level).end();iter++)
{
Function(*iter);
}
Using this gives an error:
for(iter=make.at(level).begin()+10;iter!=make.at(level).end();iter++)
{
Function(*iter);
}
There are different types of iterators: ForwardIterator, BidirectionalIterator, and RandomAccessIterator.
ForwardIterator allows you to move forward only, using the increment operator. BidirectionalIterator allows both directions. RandomAccessIterator allows any advancement, including operator+ and operator-.
The one you're thinking in terms of is RandomAccessIterator, like the one found in std::vector. What std::set uses, though, is the BidirectionalIterator. That means you can only increment and decrement.
Therefore, you need to make your iterator outside of your loop and advance it forward ten times. To make it simple, std::advance does this, and has different compatibility for BidirectionalIterator, as well as ForwardIterator (linear time because of only one increment at a time), and RandomAccessIterator (constant time due to operator+).
std::set<T>::iterator iter = make.at(level).begin(); //more C++03 way
auto iter = std::begin (make.at(level)); //more C++11 way
std::advance (iter, 10); //start iterator 10 elements past beginning
for (...)