C ++ 11 offre plusieurs façons d'itérer sur des conteneurs. Par exemple:
Boucle basée sur la plage
for(auto c : container) fun(c)
std :: for_each
for_each(container.begin(),container.end(),fun)
Cependant, quelle est la manière recommandée d'itérer sur deux (ou plus) conteneurs de même taille pour accomplir quelque chose comme:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
c++
c++11
iterator
containers
memecs
la source
la source
transform
présent dans#include <algorithm>
?containerA = containerB;
place de la boucle.Réponses:
Plutôt tard à la fête. Mais: je voudrais itérer sur les indices. Mais pas avec la
for
boucle classique mais plutôt avec unefor
boucle basée sur une plage sur les indices:indices
est une simple fonction wrapper qui renvoie une plage (évaluée paresseusement) pour les indices. Puisque l'implémentation - bien que simple - est un peu trop longue pour la publier ici, vous pouvez trouver une implémentation sur GitHub .Ce code est aussi efficace que l'utilisation d'une
for
boucle classique manuelle .Si ce modèle se produit souvent dans vos données, envisagez d'utiliser un autre modèle
zip
composé de deux séquences et produisant une plage de tuples, correspondant aux éléments appariés:La mise en œuvre de
zip
est laissée comme un exercice pour le lecteur, mais elle découle facilement de la mise en œuvre deindices
.(Avant C ++ 17, vous devriez plutôt écrire ce qui suit :)
la source
boost::counting_range(size_t(0), containerA.size())
indices
implémentation produit une sortie de compilateur qui est identique à l'utilisation defor
boucles manuelles . Il n'y a aucun frais généraux.Pour votre exemple spécifique, utilisez simplement
Pour le cas plus général, vous pouvez utiliser Boost.Iterator's
zip_iterator
, avec une petite fonction pour le rendre utilisable dans des boucles for basées sur la plage. Dans la plupart des cas, cela fonctionnera:Exemple en direct.
Cependant, pour une généricité à part entière, vous voulez probablement quelque chose de plus comme ça , qui fonctionnera correctement pour les tableaux et les types définis par l'utilisateur qui n'ont pas de membre
begin()
/end()
mais qui ontbegin
/ desend
fonctions dans leur espace de noms. En outre, cela permettra à l'utilisateur d'accéder spécifiquementconst
à travers leszip_c...
fonctions.Et si vous êtes un partisan de bons messages d'erreur, comme moi, alors vous voulez probablement ceci , qui vérifie si des conteneurs temporaires ont été passés à l'une des
zip_...
fonctions, et affiche un joli message d'erreur si c'est le cas.la source
auto
fonctionne exactement comme un paramètre de modèle, etT&&
dans un modèle se trouve une référence universelle comme expliqué dans le premier lien, doncauto&& v = 42
sera déduit commeint&&
etauto&& w = v;
sera ensuite déduit commeint&
. Il vous permet de faire correspondre lvalues ainsi que rvalues et de laisser les deux être mutables, sans faire de copie.zip_range
.je me demande pourquoi personne n'a mentionné ceci:
PS: si les tailles des conteneurs ne correspondent pas, vous devrez mettre le code dans les instructions if.
la source
Il existe de nombreuses façons de faire des choses spécifiques avec plusieurs conteneurs, comme indiqué dans l'en-
algorithm
tête. Par exemple, dans l'exemple que vous avez donné, vous pouvez utiliser à lastd::copy
place d'une boucle for explicite.D'un autre côté, il n'existe aucun moyen intégré d'itérer génériquement plusieurs conteneurs autre qu'une boucle for normale. Ce n'est pas surprenant car il existe de nombreuses façons d'itérer. Pensez-y: vous pouvez parcourir un conteneur avec une étape, un conteneur avec une autre étape; ou à travers un conteneur jusqu'à ce qu'il arrive à la fin, puis commencez à insérer pendant que vous passez à l'extrémité de l'autre conteneur; ou une étape du premier conteneur pour chaque fois que vous passez complètement par l'autre conteneur, puis recommencez; ou un autre modèle; ou plus de deux conteneurs à la fois; etc ...
Cependant, si vous souhaitez créer votre propre fonction de style "for_each" qui ne parcourt que deux conteneurs jusqu'à la longueur du plus court, vous pouvez faire quelque chose comme ceci:
Évidemment, vous pouvez faire n'importe quel type de stratégie d'itérations de la même manière.
Bien sûr, vous pourriez affirmer que faire directement la boucle for interne est plus facile que d'écrire une fonction personnalisée comme celle-ci ... et vous auriez raison, si vous ne le faites qu'une ou deux fois. Mais la bonne chose est que c'est très réutilisable. =)
la source
for (Container1::iterator i1 = c1.begin(), Container2::iterator i2 = c2.begin(); (i1 != end1) && (i2 != end2); ++it1, ++i2)
mais le compilateur crie. Quelqu'un peut-il expliquer pourquoi cela est invalide?for (int x = 0, y = 0; ...
fonctionne, maisfor (int x = 0, double y = 0; ...)
ne fonctionne pas.typename...
Dans le cas où vous devez itérer simultanément sur 2 conteneurs uniquement, il existe une version étendue de l'algorithme for_each standard dans la bibliothèque de plage de boost, par exemple:
Lorsque vous devez gérer plus de 2 conteneurs dans un seul algorithme, vous devez jouer avec zip.
la source
une autre solution pourrait être de capturer une référence de l'itérateur de l'autre conteneur dans un lambda et d'utiliser l'opérateur de post-incrémentation sur cela. par exemple, une copie simple serait:
à l'intérieur de lambda, vous pouvez faire n'importe quoi
ita
et l'incrémenter. Cela s'étend facilement au cas des conteneurs multiples.la source
Une bibliothèque de plage fournit ceci et d'autres fonctionnalités très utiles. L'exemple suivant utilise Boost.Range . Le rangev3 d'Eric Niebler devrait être une bonne alternative.
C ++ 17 rendra cela encore meilleur avec des liaisons structurées:
la source
delme.cxx:15:25: error: no match for 'operator=' (operand types are 'std::tuple<int&, char&>' and 'const boost::tuples::cons<const int&, boost::tuples::cons<const char&, boost::tuples::null_type> >') std::tie(ti,tc) = i;
^19.13.26132.0
et la version SDK Windows10.0.16299.0
):error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const boost::tuples::cons<const char &,boost::fusion::detail::build_tuple_cons<boost::fusion::single_view_iterator<Sequence,boost::mpl::int_<1>>,Last,true>::type>' (or there is no acceptable conversion)
boost::combine
: stackoverflow.com/q/55585723/8414561Je suis un peu en retard aussi; mais vous pouvez utiliser ceci (fonction variadique de style C):
ou ceci (en utilisant un pack de paramètres de fonction):
ou ceci (en utilisant une liste d'initialiseurs entre accolades):
ou vous pouvez joindre des vecteurs comme ici: Quelle est la meilleure façon de concaténer deux vecteurs? puis itérer sur un gros vecteur.
la source
Voici une variante
Exemple d'utilisation
la source