Comment utiliser la boucle for () basée sur la plage avec std :: map?


336

L'exemple courant pour les boucles for () basées sur la plage C ++ 11 est toujours quelque chose de simple comme ceci:

std::vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7 };
for ( auto xyz : numbers )
{
     std::cout << xyz << std::endl;
}

Dans ce cas, xyzest un int. Mais que se passe-t-il lorsque nous avons quelque chose comme une carte? Quel est le type de la variable dans cet exemple:

std::map< foo, bar > testing = { /*...blah...*/ };
for ( auto abc : testing )
{
    std::cout << abc << std::endl;         // ? should this give a foo? a bar?
    std::cout << abc->first << std::endl;  // ? or is abc an iterator?
}

Lorsque le conteneur traversé est quelque chose de simple, il semble que les boucles for () basées sur une plage nous donneront chaque élément, pas un itérateur. Ce qui est bien ... s'il s'agissait d'un itérateur, la première chose que nous aurions toujours à faire est de le déférencer de toute façon.

Mais je ne sais pas à quoi m'attendre quand il s'agit de choses comme les cartes et les multimaps.

(Je suis toujours sur g ++ 4.4, alors que les boucles basées sur la plage sont dans g ++ 4.6+, donc je n'ai pas encore eu l'occasion de l'essayer.)


4
La plage de déclaration fait une danse impie avec la bibliothèque standard std::beginet les std::endfonctions ou fonctions membres sous le même nom.
Gene Bushuyev

10
@will Sur un exemple de 3 lignes, vous vous faites prendre par le faux nom de variable?
Stéphane

Réponses:


495

Chaque élément du conteneur est un map<K, V>::value_type, qui est un typedefpour std::pair<const K, V>. Par conséquent, en C ++ 17 ou supérieur, vous pouvez écrire

for (auto& [key, value]: myMap) {
    std::cout << key << " has value " << value << std::endl;
}

ou comme

for (const auto& [key, value]: myMap) {
    std::cout << key << " has value " << value << std::endl;
}

si vous ne prévoyez pas de modifier les valeurs.

En C ++ 11 et C ++ 14, vous pouvez utiliser des forboucles améliorées pour extraire chaque paire par elle-même, puis extraire manuellement les clés et les valeurs:

for (const auto& kv : myMap) {
    std::cout << kv.first << " has value " << kv.second << std::endl;
}

Vous pouvez également envisager de marquer la kvvariable constsi vous souhaitez une vue en lecture seule des valeurs.


96

En C ++ 17, cela s'appelle des liaisons structurées , ce qui permet les opérations suivantes:

std::map< foo, bar > testing = { /*...blah...*/ };
for ( const auto& [ k, v ] : testing )
{
  std::cout << k << "=" << v << "\n";
}

Est-il possible d'obtenir un const &à la clé, mais une référence non const à la valeur? (parce que c'est ce que fait map :: value_type ...)
peterchen

2
@peterchen: kest constsi vous utilisezfor(auto&[k,v]:testing)
Dalle

1
cpppreference sur les liaisons structurées en.cppreference.com/w/cpp/language/structured_binding
TankorSmash

Si vous compilez avec GCC, vous avez besoin de la version 7 ou supérieure pour les liaisons structurées: gcc.gnu.org/projects/cxx-status.html
csknk

25

De cet article: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf

for( type-specifier-seq simple-declarator : expression ) statement

est syntaxiquement équivalent à

{
    typedef decltype(expression) C;
    auto&& rng(expression);
    for (auto begin(std::For<C>::begin(rng)), end(std::For<C>::end(rng)); begin != end; ++ begin) {
        type-specier-seq simple-declarator(*begin);
        statement
    }
}

Vous pouvez donc clairement voir que ce sera abcdans votre cas std::pair<key_type, value_type >. Donc, pour l'impression, vous pouvez accéder à chaque élément par abc.firstetabc.second



3

Si l'opérateur d'affectation de copie de foo et bar est bon marché (par exemple, int, char, pointer, etc.), vous pouvez effectuer les opérations suivantes:

foo f; bar b;
BOOST_FOREACH(boost::tie(f,b),testing)
{
  cout << "Foo is " << f << " Bar is " << b;
}

4
Le premier extrait de code n'utilise pas de "plage C ++ 11 basée sur ()". Ce n'est pas une réponse à "C ++ 11: comment utiliser la boucle for () basée sur une plage avec std :: map?"
isoiphone

1
@ytj Il est déjà mentionné dans la réponse que cela ne fonctionne pas. Je ne veux pas supprimer cela pour que les nouveaux utilisateurs n'aient pas à l'essayer et à le découvrir à nouveau.
balki
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.