简体   繁体   中英

Why do std::generate() and std::generate_n() require different iterators?

I was looking at generate() and generate_n() in cppreference and am trying to understand why does generate() require ForwardIterator , whereas generate_n() requires OutputIterator for the range? (I checked the latest working draft of the Standard, and it's the same requirement.)

Because, at least their possible implementations seem to require identical iterator concepts and OutputIterator seems to be enough:

generate() :

template<class ForwardIt, class Generator>
void generate(ForwardIt first, ForwardIt last, Generator g)
{
    while (first != last) {
        *first++ = g();
    }
}

generate_n() :

template<class OutputIt, class Size, class Generator>
OutputIt generate_n(OutputIt first, Size count, Generator g)
{
    for (Size i = 0; i < count; i++) {
        *first++ = g();
    }
    return first;
}

Same story with std::fill() and std::fill_n() .

at least their possible implementations seem to require identical iterator concept and OutputIterator seems to be enough

OutputIterator doesn't support equality / inequality comparison (including operator!= used in the possible implementation of generate() you showed) and multipass guarantee, while ForwardIterator does. That means OutputIterator can't be used for representing a range via two iterators (eg [first, last) ) which is required by generate() 's interface.

Equality and inequality may not be defined for output iterators. Even if an operator== is defined, x == y need not imply ++x == ++y.

songyuanyao's answer explains the matter from a technical viewpoint. I'll try to provide a bit more informal explanation.

Many STL algorithms, including generate and fill , are applied to a number of items. The way an algorithm must be able to access those items defines the requirements for the iterator.

In your case, the definition of generate contains:

...
while (first != last) {  // implies that Iter implements operator!=
  *first++;              // implies that Iter implements operator++

While the second requirement seems to be satisfied by any iterator type (after all, that's what iterators are all about — iterating over things :)), the support for comparison operator!= is provided by not all iterator types.

For instance, you cannot use ostream_iterator for std::generate . But, you can, eg , output a fixed number of generated values into a stream via std::generate_n .

Here's a very artificial example at Coliru . Once I start thinking about real-life applications, I'd guess the ability to work with OutputIterators may be useful for implementing some serialization logic.

generate() and generate_n() , like all the standard library algorithms, operate on a range , that is, a sequence of values accessed through an iterator. In order to apply an operation to all of the elements of a range the algorithm has to know where the range begins and where it ends. There are two common ways of giving it that information: you can specify the range with an iterator and a length, and use a loop of the form while (length-- != 0) { ... ++first; } while (length-- != 0) { ... ++first; } ; or you can specify the range with a pair of iterators [first, last) and use a loop of the form while (first != last) { ... ++first; } while (first != last) { ... ++first; } .

For the first version, you need to be able to increment the iterator and, for these algorithms, write a value through the iterator. Those are the main properaties of a output iterator , and that's all you need for generate_n() .

For the second version, you need to be able to increment the iterator and write a value through the iterator, just like the first version. You also have to be able to compare two iterators for equality, and an output iterator doesn't support that; you have to have at least a forward iterator . That's why generate() , which takes a range designated by a pair of iterators, requires a forward iterator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM