Wie verwende ich die range-basierte for () Schleife mit std :: map?

Das gängige Beispiel für C ++ 11-basierte for () -Schleifen ist immer etwas Einfaches:

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

Wenn der Container, der durchlaufen wird, etwas Einfaches ist, sieht es so aus, als ob bereichsbasierte for () – Schleifen uns jedes Element und keinen Iterator geben würden. Was schön ist … wenn es ein Iterator wäre, müssten wir als erstes immer noch deneferenzieren.

Aber ich bin verwirrt, was zu erwarten ist, wenn es um Karten und Multimaps geht.

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

Jedes Element des Containers ist eine map::value_type , die ein typedef für std::pair . Folglich würden Sie dies als schreiben

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

Aus Gründen der Effizienz empfiehlt es sich, den Parameter in der Schleife als Referenz zu definieren. Sie könnten auch in Betracht ziehen, es const wenn Sie eine schreibgeschützte Ansicht der Werte wünschen.

In C ++ 17 nennt man das strukturierte Bindungen , was folgendes ermöglicht:

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

Aus diesem Papier: 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::begin(rng)), end(std::For::end(rng)); begin != end; ++ begin) { type-specifier-seq simple-declarator(*begin); statement } } 

Sie können also klar sehen, dass abc in Ihrem Fall std::pair . Zum Drucken können Sie also auf jedes Element mit abc.first und abc.second

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

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

Es gibt ein entsprechendes boost :: adapter :: key_values

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

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

BEARBEITEN : Das Folgende funktioniert nicht wie zuvor : Es muss eine Deklaration sein , kein Lvalue- Ausdruck .

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