Wie verwende ich eine bereichsbasierte for () - Schleife mit std :: map?


336

Das gängige Beispiel für bereichsbasierte for () - Schleifen in C ++ 11 ist immer so einfach:

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

In welchem ​​Fall xyzist ein int. Aber was passiert, wenn wir so etwas wie eine Karte haben? Was ist der Typ der Variablen in diesem Beispiel:

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?
}

Wenn der zu durchlaufende Container etwas Einfaches ist, sieht es so aus, als würden bereichsbasierte for () -Schleifen uns jedes Element geben, keinen Iterator. Was schön ist ... wenn es ein Iterator wäre, müssten wir es immer als erstes dereferenzieren.

Aber ich bin verwirrt, was mich erwartet, wenn es um Dinge wie Karten und Multimaps geht.

(Ich bin immer noch auf g ++ 4.4, während bereichsbasierte Schleifen in g ++ 4.6+ sind, also hatte ich noch keine Gelegenheit, es zu versuchen.)


4
Der Bereich für Anweisungen führt einen unheiligen Tanz mit der Standardbibliothek std::beginund std::endFunktionen oder Mitgliedsfunktionen unter demselben Namen durch.
Gene Bushuyev

10
@will In einem dreizeiligen Beispiel werden Sie vom falschen Variablennamen erfasst?
Stéphane

Antworten:


495

Jedes Element des Containers ist ein map<K, V>::value_type, was ein typedeffür ist std::pair<const K, V>. Folglich können Sie in C ++ 17 oder höher schreiben

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

oder als

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

Wenn Sie nicht vorhaben, die Werte zu ändern.

In C ++ 11 und C ++ 14 können Sie erweiterte forSchleifen verwenden, um jedes Paar einzeln zu extrahieren und anschließend die Schlüssel und Werte manuell zu extrahieren:

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

Sie können die kvVariable auch markieren , constwenn Sie eine schreibgeschützte Ansicht der Werte wünschen.


95

In C ++ 17 wird dies als strukturierte Bindung bezeichnet , was Folgendes ermöglicht:

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

Ist es möglich, einen const &zum Schlüssel zu bekommen , aber einen nicht konstanten Verweis auf den Wert? (weil das ist, was map :: value_type macht ...)
Peterchen

2
@ Peterchen: kist, constwenn Sie verwendenfor(auto&[k,v]:testing)
dalle

1
cpppreference auf strukturierten Bindungen en.cppreference.com/w/cpp/language/structured_binding
TankorSmash

Wenn Sie mit GCC kompilieren, benötigen Sie Version 7 oder besser für strukturierte Bindungen: gcc.gnu.org/projects/cxx-status.html
csknk

25

Aus diesem Artikel: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf

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

ist syntaktisch äquivalent zu

{
    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
    }
}

So können Sie deutlich sehen, was abcin Ihrem Fall sein wird std::pair<key_type, value_type >. So zum Drucken Sie können jedes Element Zugriff tun durch abc.firstundabc.second



3

Wenn der Kopierzuweisungsoperator von foo und bar billig ist (z. B. int, char, pointer usw.), können Sie Folgendes tun:

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

4
Der erste Codeausschnitt verwendet kein "C ++ 11-Bereich-basiertes für ()". Es ist keine Antwort auf "C ++ 11: Wie verwende ich eine bereichsbasierte for () - Schleife mit std :: map?"
Isoiphone

1
@ytj In der Antwort wird bereits erwähnt, dass es nicht funktioniert. Ich möchte das nicht entfernen, damit neue Benutzer es nicht versuchen und die Tatsache erneut herausfinden müssen.
Balki
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.