169 votos

C ++ 11: Cómo utilizar el bucle for() basados en rangos con std::map?

El ejemplo común para C++0x gama basada por(a) los bucles siempre es algo simple como esto:

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

En cuyo caso, xyz es int. Pero, ¿qué pasa cuando tenemos algo así como un mapa? ¿Cuál es el tipo de la variable en este ejemplo:

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

Cuando el contenedor se recorren es algo simple, se ve como la gama basada por(a) los bucles nos dará a cada elemento, no un iterador. Lo cual es bueno...si era iterador, la primera cosa que siempre iba a tener que hacer es eliminar la referencia de todos modos.

Pero estoy confundido en cuanto a qué esperar cuando se trata de cosas como mapas y multimaps.

(Todavía estoy en g++ 4.4, mientras que la gama basada en bucles son en g++ 4.6+, así que no he tenido la oportunidad de probar aún).

228voto

templatetypedef Puntos 129554

Cada elemento del contenedor es un map<K, V>::value_type , que es un typedef para std::pair<const K, V> . En consecuencia, debería escribir esto como

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

Para la eficiencia, es una buena idea hacer el parámetro en el bucle de referencia. Usted también podría considerar lo que const si quieres una vista de sólo lectura de los valores.

22voto

Aditya Kumar Puntos 3884

De este artículo: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf

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

sintácticamente 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
    }
}

Así se puede ver claramente que lo que es abc en su caso será std::pair<key_type, value_type > . Así que puedes hacer para la impresión de acceder a cada elemento por abc.first yabc.second

4voto

Pixie-Poop Puntos 21

Si sólo desea ver los valores o claves de tu mapa y como usar boost, puede utilizar los adaptadores de impulso con los bucles gama basada:

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

Hay una boost::adaptors::key_values equivalente

http://www.Boost.org/doc/libs/1_51_0/libs/Range/doc/HTML/Range/Reference/Adaptors/Reference/map_values.html

3voto

balki Puntos 4786

Si el operador de asignación copia de foo y bar es barato (ej. int, char, puntero, etc.), puedes hacer lo siguiente:

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

Editar: el abajo no funciona como antes : , tiene que ser una declaración, no lvalue expresión.

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

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: