it-swarm.com.de

Wie verwende ich range-based for () loop mit std :: map?

Das übliche Beispiel für C++ 11-bereichsbasierte for () -Schleifen 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 diesem Fall ist xyz 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 es sich bei dem Container, der durchlaufen wird, um etwas Einfaches handelt, sieht es so aus, als ob bereichsbezogene for () -Schleifen uns jedes Element und keinen Iterator geben. Was Nizza ist ... Wenn es ein Iterator wäre, müssten wir es sowieso als erstes dereferenzieren.

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

(Ich arbeite immer noch mit g ++ 4.4, während bereichsbezogene Loops in g ++ 4.6+ sind. Daher hatte ich noch keine Chance, es zu versuchen.)

308
Stéphane

Jedes Element des Containers ist ein map<K, V>::value_type, das ist ein typedef für 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 die Werte nicht ändern möchten.

In C++ 11 und C++ 14 können Sie erweiterte for - Schleifen verwenden, um jedes Paar für sich zu extrahieren und dann die Schlüssel und Werte manuell zu extrahieren:

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

Sie können auch die Variable kvconst markieren, wenn Sie eine schreibgeschützte Ansicht der Werte wünschen.

442
templatetypedef

In C++ 17 heißt dies strukturierte Bindungen , was Folgendes ermöglicht:

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

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-specifier-seq simple-declarator(*begin);
        statement
    }
}

Sie können also deutlich erkennen, dass abc in Ihrem Fall std::pair<key_type, value_type > Ist. Zum Drucken können Sie also auf jedes Element mit abc.first Und abc.second Zugreifen.

25
A. K.

Wenn Sie nur die Schlüssel/Werte von Ihrer Karte sehen möchten und Boost verwenden möchten, können Sie die Boost-Adapter mit den bereichsbasierten Schleifen verwenden:

for (const auto& value : myMap | boost::adaptors::map_values)
{
    std::cout << value << std::endl;
}

es gibt ein äquivalentes boost :: adapters :: key_values

http://www.boost.org/doc/libs/1_51_0/libs/range/doc/html/range/reference/adaptors/reference/map_values.html

14
Pixie-Poop

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;
}
2
balki