Come utilizzare il range-based per () loop con std :: map?


336

L'esempio comune per i loop () basati su intervallo C ++ 11 è sempre qualcosa di semplice come questo:

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

Nel qual caso xyzè un int. Ma cosa succede quando abbiamo qualcosa come una mappa? Qual è il tipo di variabile in questo esempio:

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

Quando il contenitore attraversato è qualcosa di semplice, sembra che i cicli () basati sulla portata ci forniscano ogni elemento, non un iteratore. Il che è bello ... se fosse iteratore, la prima cosa che dovremmo sempre fare è dereferenziarlo comunque.

Ma sono confuso su cosa aspettarsi quando si tratta di cose come mappe e multimappa.

(Sono ancora su g ++ 4.4, mentre i loop basati su range sono in g ++ 4.6+, quindi non ho ancora avuto la possibilità di provarlo.)


4
L'intervallo per l'affermazione fa una danza empia con la libreria standard std::begine le std::endfunzioni o le funzioni membro con lo stesso nome.
Gene Bushuyev il

10
@will In un esempio di 3 righe, vieni catturato dal nome della variabile falsa?
Stéphane,

Risposte:


495

Ogni elemento del contenitore è un map<K, V>::value_type, che è un typedeffor std::pair<const K, V>. Di conseguenza, in C ++ 17 o versioni successive, è possibile scrivere

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

o come

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

se non prevedi di modificare i valori.

In C ++ 11 e C ++ 14, è possibile utilizzare forloop avanzati per estrarre ciascuna coppia da sola, quindi estrarre manualmente le chiavi e i valori:

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

Puoi anche considerare di contrassegnare la kvvariabile constse desideri una vista di sola lettura dei valori.


96

In C ++ 17 questo è chiamato binding strutturato , che consente quanto segue:

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

È possibile ottenere un const &alla chiave, ma un riferimento non const al valore? (perché è quello che fa map :: value_type ...)
peterchen

2
@peterchen: kè constse usifor(auto&[k,v]:testing)
dalle

1
cpppreference su associazioni strutturate en.cppreference.com/w/cpp/language/structured_binding
TankorSmash

Se stai compilando con GCC hai bisogno della versione 7 o superiore per i collegamenti strutturati: gcc.gnu.org/projects/cxx-status.html
csknk,

25

Da questo documento: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf

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

è sintatticamente equivalente a

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

Quindi puoi vedere chiaramente che cosa sarà abcnel tuo caso std::pair<key_type, value_type >. Quindi per la stampa puoi accedere a ciascun elemento con abc.firsteabc.second



3

Se l'operatore di assegnazione della copia di foo and bar è economico (ad es. Int, char, pointer ecc), è possibile effettuare le seguenti operazioni:

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

4
Il primo frammento di codice non utilizza un "C ++ 11 basato su intervallo per ()". Non è una risposta a "C ++ 11: come utilizzare range-based per () loop con std :: map?"
isoiphone

1
@ytj È già stato menzionato nella risposta che non funziona. Non voglio rimuoverlo in modo che i nuovi utenti non debbano provarlo e scoprire di nuovo il fatto.
balki,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.