28 votes

Pourquoi std :: generate () et std :: generate_n () nécessitent-ils des itérateurs différents?

Je regardais generate() et generate_n() dans cppreference et essaie de comprendre pourquoi est - generate() besoin ForwardIterator, alors que generate_n() exige OutputIterator pour la gamme? (J'ai vérifié la dernière ébauche de la Norme, et c'est la même exigence.)

Parce que, au moins leurs implémentations possibles semblent exiger identiques concepts d'itérateur et OutputIterator semble être suffisant:

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;
}

Même histoire avec std::fill() et std::fill_n().

38voto

songyuanyao Points 2265

au moins leurs implémentations possibles semblent exiger identiques concept itérateur et OutputIterator semble être assez

OutputIterator ne prend pas en charge l'égalité / l'inégalité de comparaison (y compris operator!= utilisé dans la mise en œuvre d' generate() vous a montré) et multipass garantie, tandis que ForwardIterator n'. Cela signifie que OutputIterator ne peut pas être utilisé pour représenter une gamme via deux itérateurs (par exemple, [first, last)) qui est requis par generate()'s de l'interface.

L'égalité et l'inégalité ne peut pas être définie pour la sortie des itérateurs. Même si un opérateur== est défini, x == y n'implique pas nécessairement ++x == ++y).

9voto

Vasiliy Galkin Points 1312

songyuanyao la réponse de explique la chose d'un point de vue technique. Je vais essayer d'apporter un peu plus d'explication informelle.

De nombreux algorithmes de la STL, y compris generate et fill, sont appliqués à un certain nombre d'éléments. Un algorithme doit être en mesure d'accéder à ces éléments définit les exigences pour l'itérateur.

Dans votre cas, la définition de l' generate contient:

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

Tandis que la seconde exigence semble être satisfaits par un itérateur de type (après tout, c'est ce que les itérateurs sont tout au sujet - l'itération sur les choses :)), le soutien pour la comparaison, operator!= est fourni par pas tous les types iterator.

Par exemple, vous ne pouvez pas utiliser ostream_iterator pour std::generate. Mais, vous pouvez, par exemple, la sortie d'un nombre fixe de valeurs générées dans un cours d'eau via std::generate_n.

Voici un très artificielle exemple à Coliru. Une fois que j'ai commencer à penser à des applications réelles, je suppose la capacité à travailler avec des OutputIterators peut être utile pour la mise en œuvre de certaines logique de sérialisation.

8voto

Pete Becker Points 27371

generate() et generate_n(), comme tous les algorithmes de la bibliothèque standard, de faire fonctionner sur une plage, c'est une séquence de valeurs accessibles via un itérateur. Afin d'appliquer une opération pour tous les éléments d'une plage de l'algorithme est de savoir où la gamme commence et où elle se termine. Il y a deux façons de donner des informations: vous pouvez spécifier la plage avec un itérateur et d'une longueur, et l'utilisation d'une boucle de la forme while (length-- != 0) { ... ++first; }; ou vous pouvez spécifier la plage avec une paire d'itérateurs [first, last) et l'utilisation d'une boucle de la forme while (first != last) { ... ++first; }.

Pour la première version, vous devez être en mesure d'augmenter l'itérateur et, pour ces algorithmes, d'écrire une valeur par l'itérateur. Ce sont les principaux properaties d'une sortie d'itérateur, et c'est tout ce dont vous avez besoin pour generate_n().

Pour la deuxième version, vous devez être en mesure d'incrémenter la variable d'itération et d'écrire une valeur par l'itérateur, tout comme la première version. Vous aussi devez être en mesure de comparer les deux itérateurs pour l'égalité, et une sortie itérateur ne supporte pas que; vous devez avoir au moins un avant itérateur. C'est pourquoi, generate(), qui prend une plage désignée par une paire d'itérateurs, nécessite un avant itérateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X