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 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 include / g ++ - v4 / bits / vector.tcc code>:
std :: Forwe_Iderator_TAG code > 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? P> P>
5 Réponses :
au risque de cibler votre lien ..
classe vide pour identifier la catégorie d'un itérateur comme itérateur avant: p> blockQuote>
Il est utilisé comme étiquette pour identifier le type d'itérateur, de sorte que les fonctions, ici
_m_range_insert code> 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. P>
dans mon implément, j'ai p>
xxx pré> parmi d'autres surcharges. p> p>
à distinguer entre différents 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 . p> _m_range_insert code> surcharges. p>
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 code> à la surcharge code> _m_range_insert code> qui attend un
Forward_iterator_tag code>, car c'est juste une conversion dérivée à base.
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. P>
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 code> Karthik mentionné, Wich est utilisé pour le
(Taille_t, valeur_type) code> surcharge .
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());
}
C'est pas i> 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 code> pour tous les itérateurs qui prennent en charge
std :: Distance> STD :: Distance Code> ou uniquement pour insérer des itérateurs d'entrée simples ou de redirection vers
Insérer (POS, Compte, Valeur) code> 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 ..." I>. OP est posé sur la nécessité de std :: Forward_iterator_tag code>, et l'idée des balises est la même pour
insérer code> et
avance code>. Évidemment, il est préférable d'utiliser une méthode simple b> comme exemple B> pour illustrer l'idée b> 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 i>, où j'avais appris celles-ci. De l'autre côté, je ne peux pas trouver où _m_range_insert code> est utilisé, ce n'est pas à la main i> pour moi. Et, bien que peut-être insérer n'est pas beaucoup i> plus complexe, c'est plus i> complexe.
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é: si vous avez un 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: p> Vous aurez alors un tas de surcharges de La méthode d'insertion modélisée semblera ensuite conceptuellement comme celle-ci: p> vecteur
vec.insert (Vec.bgein (), 5, 4) Code>, 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 code> pour être
int code>. P>
_int_iterator_tag code> si
INPUTITE code> est de type intégré li>
forward_iterator_tag code> si
INPUTIT code> est un itérateur avant (qui inclut des itérateurs d'accès aléatoire) li>
INPUT_ITERATOR_TAG CODE> Si
InputIt code> est un type d'itérateur qui n'est pas un itérateur avant li>
ul>
_m_range_insert code>, en prenant les différents types d'étiquettes sous forme de paramètres supplémentaires, chacun faisant la bonne chose, ce qui signifie p>
Insérer code> (ou sa mise en œuvre) li>
réserve (STD :: Distance (premier, dernier)) CODE> et copie les éléments de la plage d'itérateurs après que LI>
réserve code>, car les itérateurs d'entrée ne peuvent être évalués qu'une seule fois (chose par exemple d'itérateurs iStream) li>
ul>
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. B> stl n'est pas une si mauvaise bibliothèque. Peut-être que vous devriez être correct dans insérer code>, 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 i>.
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)
Éventuellement de distinguer entre différents
_m_range_insert code> 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 code>. (jamais essayé de rouler votre propre
std :: vecteur code> implémentation? :-))