8
votes

Quel est le rôle de std :: forward_iterator_tag?

Lors du profilage d'une application, j'ai heurté cette pièce de la mise en œuvre de la bibliothèque standard expédiée avec GCC 4.7.1. Il est include / g ++ - v4 / bits / vector.tcc : xxx

J'ai remarqué que le dernier argument de la signature de fonction est juste une étiquette et j'ai commencé Vous vous demandez pourquoi c'était ici. Un aspect rapide sur Cette page montre que std :: Forwe_Iderator_TAG est une structure vide. Quel est son rôle ici? Clairement, il est inutile de la fonction, et cela pourrait gaspiller un registre, ou un espace sur la pile. Alors pourquoi?


3 commentaires

Éventuellement de distinguer entre différents _m_range_insert surcharges? Cette référence semble un peu meilleure et a un exemple sur la manière dont la structure des étiquettes peut être utilisé.


@ JohatMimpileborg: Oui. Et c'est aussi une réponse. S'il vous plaît poster cela comme une réponse.


@ JooSimpileborg Tout en distinguant les surcharges, les surcharges réelles et leur utilisation peuvent être plus importantes que les étiquettes fournies par la norme, à savoir _int_iterator_tag . (jamais essayé de rouler votre propre std :: vecteur implémentation? :-))


5 Réponses :


4
votes

au risque de cibler votre lien ..

classe vide pour identifier la catégorie d'un itérateur comme itérateur avant:

Il est utilisé comme étiquette pour identifier le type d'itérateur, de sorte que les fonctions, ici _m_range_insert peut agir de manière appropriée. Comme il s'agit d'un nom de type, il peut être utilisé pour déclencher différentes surcharges.

dans mon implément, j'ai xxx

parmi d'autres surcharges.


0 commentaires

6
votes

à distinguer entre différents _m_range_insert surcharges.

Cette référence semble un peu meilleure et a un exemple sur la manière dont les structures de balises peuvent être utilisées .


1 commentaires

Le bit important est que les types de balises sont liés par héritage. Vous pouvez transmettre un aléatoire_access_itérator_tag à la surcharge _m_range_insert qui attend un Forward_iterator_tag , car c'est juste une conversion dérivée à base.



1
votes

Fait partie des machines de métaprogrammation de modèle et il est utilisé pour choisir la surcharge appropriée en fonction des traits d'arguments, par exemple si vous avez des itérateurs d'accès aléatoires, vous pouvez en tirer parti et vérifier la distance entre eux et réserver avant d'inserrer. D'autre part, si vous n'avez que la distance de vérification des itérateurs d'itérateurs d'itérateurs. Le compilateur optimisera également ces structs vides, il n'y a donc pas de pénalité d'exécution.


4 commentaires

Je ne sais pas quelle est la mise en œuvre, mais je suppose que cela préférera prendre le chèque de distance O (n) que les copies O (n) des copies sur la réaffectation.


La réaffectation est possible, mais pas garantie et le coût de la distance de contrôle est garantie, il s'agit donc de l'amortissement envisageant une utilisation moyenne. Et je pense que le plus souvent, vous insérez moins d'éléments que le vecteur contient déjà. Quoi qu'il en soit, cela était signifié comme un exemple pour l'utilisation des balises et le point clé, c'est que cela vous donne des informations si la distance (IT1, IT2) est O (1) ou O (n), que vous n'auriez pas autrement et comment vous utilisez cette information ISN 't aussi important


vous avez raison sur l'arne, il fait vérifier la distance dans ma mise en œuvre, j'ai choisi un mauvais exemple, il y a toujours d'autres différences


La différence est que les itérateurs d'entrée pure ne peuvent pas vérifier la différence, et je pense que la balise la plus importante est le _int_iterator_tag Karthik mentionné, Wich est utilisé pour le (Taille_t, valeur_type) surcharge .



11
votes

En bref: les balises sont pour la surcharge, pour optimisation.

Prendre un simple ADVANCE code> AS exemple, vous pourriez concevoir: p>

template<class II, class D>
void __advance(II& i, D n, input_iterator_tag){
    while( n-- ) ++i;
}

template<class RAI, class D>
void __advance(RAI& i, D n, random_access_iterator_tag){
    i += n;
}

template<class II, class D>
void advance(II& i, D n){
    __advance(i, n, iterator_traits<II>::iterator_category());
}


4 commentaires

C'est pas de faire avancer les itérateurs, car il n'est pas nécessaire de ne pas être fait. En fait, vous ne pouvez même pas faire avancer les itérateurs d'intrants purs comme celui-ci sans les invalider. Les balises portent sur Calling réserve pour tous les itérateurs qui prennent en charge std :: Distance> STD :: Distance ou uniquement pour insérer des itérateurs d'entrée simples ou de redirection vers Insérer (POS, Compte, Valeur) si les "itérateurs" sont en réalité des entiers. Voir ma réponse pour plus de détails.


Ma première phrase: "Prenez une simple avancée comme exemple ..." . OP est posé sur la nécessité de std :: Forward_iterator_tag , et l'idée des balises est la même pour insérer et avance . Évidemment, il est préférable d'utiliser une méthode simple comme exemple pour illustrer l'idée des balises.


Si j'accepte qu'un exemple simple pour illustrer l'idée est un bon choix, je ne pense pas que le cas d'utilisation réel à la main est tellement plus complexe que le simple exemple que vous avez fourni. Bien que je me trompe à propos de l'invalidation des itérateurs d'entrée sur incréments - je m'excuse pour cela.


J'ai un livre à la main , où j'avais appris celles-ci. De l'autre côté, je ne peux pas trouver où _m_range_insert est utilisé, ce n'est pas à la main pour moi. Et, bien que peut-être insérer n'est pas beaucoup plus complexe, c'est plus complexe.



1
votes

Il existe plusieurs surcharges pour l'insertion dans un vecteur, certains d'entre eux sont dupliqués pour les constructeurs. Deux de ces surcharges ont un conflit si les éléments vectoriels sont de type intégré: xxx

si vous avez un vecteur et appelez vec.insert (Vec.bgein (), 5, 4) , vous voulez sûrement insérer 5 fois la valeur de la valeur 4. Mais la résolution de la surcharge verra le modèle et l'appelez celui-ci, déduire entrée pour être int .

Pour résoudre ce problème et d'autres éléments de comportement, les implémentations de la bibliothèque standard ont inventé des traits et un tas de classes de balises. Les traits sont un modèle métafuncifonction qui donnera trois étiquettes différentes, comme Karthik T dit dans sa réponse:

  • _int_iterator_tag si INPUTITE est de type intégré
  • forward_iterator_tag si INPUTIT est un itérateur avant (qui inclut des itérateurs d'accès aléatoire)
  • INPUT_ITERATOR_TAG Si InputIt est un type d'itérateur qui n'est pas un itérateur avant

    Vous aurez alors un tas de surcharges de _m_range_insert , en prenant les différents types d'étiquettes sous forme de paramètres supplémentaires, chacun faisant la bonne chose, ce qui signifie

    • La surcharge de l'étiquette INT redirigera à la première surcharge non modenée de Insérer (ou sa mise en œuvre)
    • La surcharge pour les appels d'itérateurs transfrontières réserve (STD :: Distance (premier, dernier)) et copie les éléments de la plage d'itérateurs après que
    • La surcharge pour les itérateurs d'entrée ordinaire, copie simplement les éléments, peut-être causer plusieurs réaffectations. Il ne peut pas appeler réserve , car les itérateurs d'entrée ne peuvent être évalués qu'une seule fois (chose par exemple d'itérateurs iStream)

      La méthode d'insertion modélisée semblera ensuite conceptuellement comme celle-ci: xxx


4 commentaires

Ce n'est pas le rôle des traits. Si la résolution de la surcharge est un problème, STL changerait simplement le nom. stl n'est pas une si mauvaise bibliothèque. Peut-être que vous devriez être correct dans insérer , mais vous ne le ferez pas dans une autre fonction.


Je n'ai jamais dit que les tags avaient le rôle des traits. Les balises sont utilisées pour la résolution de la surcharge et les traits sont utilisés pour générer des balises à partir du paramètre de modèle.


Il semble que nous pensions à différentes choses. Vous pensez que les balises sont utilisées pour la résolution de la surcharge, tandis que je pense que des balises sont utilisées pour la résolution de surcharge pour optimisation .


Ah ... J'ai essayé d'annuler la baisse vote, mais le système m'a interdit. (Vous avez voté pour la dernière fois sur cette réponse il y a 23 minutes. Votre vote est maintenant verrouillé à moins que cette réponse soit modifiée)