2011-07-15 3 views
0

à this answer vous référant, le deuxième bloc de code. Ma question est:retour std :: liste cuvette itérateur pas en utilisant des modèles

Si je sais que je vais traiter seulement std::lists<int>, et seulement <int>. Existe-t-il un moyen d'écrire ceci (le deuxième bloc et le troisième) sans utiliser de modèles et sans passer la liste par référence comme suggéré dans les commentaires? Pourriez-vous me le montrer?

Je pense qu'il est logique d'éviter d'utiliser des modèles si la mise en œuvre ne couvre qu'un seul droit unique de type ??? (Ou suis-je trop paresseux?)

Répondre

4

Voilà ma réponse!

Vous pouvez passer un std::back_insert_iterator<std::list<int> > à une fonction avec ou sans modèles. Secrètement, vous passez toujours la liste par référence, puisque l'itérateur lui-même contient une référence ou un pointeur vers le conteneur.

typedef std::back_insert_iterator<std::list<int> > OutputIterator; 

void getInts(OutputIterator out) { 
    for (int i = 0; i < 10; ++i) { 
     *(out++) = i; 
    } 
} 

Ensuite, l'appelant fait:

std::list<int> l; 
getInts(std::back_inserter(l)); 

Vous êtes toujours « à l'aide des modèles » dans le sens où back_inserter est un modèle de fonction et back_insert_iterator est un modèle de classe, mais là encore est si list . De cette façon, vous n'écrivez aucun modèle de votre choix. Je ne suis pas d'accord qu'il est nécessaire d'éviter les modèles si vous êtes seulement intéressé par un type - un effet secondaire des modèles C++ est l'inférence de type via la déduction des arguments de modèle, ce qui signifie que vous n'avez pas à écrire types ridicules comme std::back_insert_iterator<std::list<int> >, même une fois dans un typedef. Comme vous pouvez le voir dans le code, éviter les modèles n'est pas de la paresse, c'est en fait moins de texte pour écrire le modèle précisément parce que vous n'avez pas besoin de mentionner les types. Mais si pour une raison quelconque, vous voulez sortir de votre façon de limiter qui fonctionnent à fonctionner uniquement avec des listes, et seulement avec annexant à l'arrière d'eux, alors vous pouvez aller de l'avant.

+0

vous êtes grand! et merci pour la clarification. En attendant, j'ai déjà implémenté votre premier exemple dans mon code, et après cette réponse je ne pense pas que je vais le changer. Je pourrais ouvrir une autre question si vous voulez mais pourriez-vous nous parler de la partie '* (out ++)'? Quelle est cette construction? Où puis-je lire à ce sujet? Juste une syntaxe itérative typique? –

+1

@quiuquio: oui, c'est juste l'idiome pour écrire dans un itérateur de sortie. C'est une exigence que les itérateurs de sortie supportent (24.1.2, tableau 73), mais c'est plus ou moins équivalent à '* out = i; ++ out; '- affecte la valeur à l'itérateur déréférencé, puis l'incrémente pour la valeur suivante. Je dis "plus ou moins", car il a la même signification définie en ce qui concerne l'interface d'itérateur, mais rien n'arrête réellement un itérateur ayant des effets secondaires différents pour le post-incrément et le pré-incrément, ou pour assigner par copie contre original, donc ce n'est pas tout à fait identique. –

+0

Oh, et la * raison * qui est l'idiome pour les itérateurs, c'est que les itérateurs sont conçus comme une généralisation des pointeurs. La syntaxe d'utilisation d'un itérateur de sortie est la même que l'utilisation d'un pointeur pour remplir un tableau - écrire dans l'élément courant, puis incrémenter. Une API avec plus d'objets peut avoir un seul appel de fonction qui écrit une valeur et avance en une fois, mais alors les pointeurs ne seront pas des itérateurs, donc C++ ne le fait pas comme ça. –

Questions connexes