it-swarm.dev

Come usare il ciclo per-range per () con std :: map?

L'esempio comune dei cicli for () 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 che viene attraversato è qualcosa di semplice, sembra che i cicli for () basati su intervalli ci forniscano ciascun elemento, non un iteratore. 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 multimaps.

(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.)

301
Stéphane

Ogni elemento del contenitore è un map<K, V>::value_type, che è un typedef per std::pair<const K, V>. Di conseguenza, lo scriverebbe come

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

Per efficienza, è una buona idea rendere il parametro nel loop un riferimento. Si potrebbe anche considerare di renderlo const se si desidera una visualizzazione di sola lettura dei valori.

A partire da C++ 17, puoi anche scrivere

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

che è molto più pulito.

429
templatetypedef

In C++ 17 questo è chiamato collegamenti strutturati , che consente quanto segue:

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

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

Quindi puoi vedere chiaramente che cos'è abc nel tuo caso sarà std::pair<key_type, value_type >. Quindi per la stampa puoi accedere ad ogni elemento con abc.first e abc.second

25
A. K.

Se vuoi solo vedere le chiavi/i valori dalla tua mappa e come usare boost, puoi usare gli adattatori boost con i loop basati su intervalli:

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

c'è un boost equivalente :: adapters :: key_values

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

13
Pixie-Poop

Se l'operatore di assegnazione copia di foo e bar è economico (ad esempio int, char, puntatore, ecc.), Puoi eseguire le seguenti operazioni:

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