¿Cómo usar el bucle for () basado en rango con std :: map?


336

El ejemplo común para los bucles para () basados ​​en el rango de C ++ 11 es siempre 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 xyzes un int. Pero, ¿qué sucede cuando tenemos algo 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 que se atraviesa es algo simple, parece que los bucles basados ​​en rango para () nos darán cada elemento, no un iterador. Lo que es bueno ... si fuera iterador, lo primero que siempre tendríamos que hacer es desreferenciarlo de todos modos.

Pero estoy confundido sobre qué esperar cuando se trata de cosas como mapas y mapas múltiples.

(Todavía estoy en g ++ 4.4, mientras que los bucles basados ​​en rango están en g ++ 4.6+, por lo que aún no he tenido la oportunidad de probarlo).


44
El rango para la declaración hace un baile profano con la biblioteca estándar std::beginy las std::endfunciones o funciones miembro bajo el mismo nombre.
Gene Bushuyev

10
@will En un ejemplo de 3 líneas, ¿estás atrapado en el nombre falso de la variable?
Stéphane

Respuestas:


495

Cada elemento del contenedor es un map<K, V>::value_type, que es un typedefpara std::pair<const K, V>. En consecuencia, en C ++ 17 o superior, puede escribir

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

o como

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

si no planeas modificar los valores.

En C ++ 11 y C ++ 14, puede usar forbucles mejorados para extraer cada par por sí mismo, luego extraer manualmente las claves y los valores:

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

También podría considerar marcar la kvvariable constsi desea una vista de solo lectura de los valores.


96

En C ++ 17 esto se llama enlaces estructurados , lo que permite lo siguiente:

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

¿Es posible obtener un const &a la clave, pero una referencia no constante al valor? (porque eso es lo que hace map :: value_type ...)
peterchen

2
@peterchen: kes constsi lo usasfor(auto&[k,v]:testing)
dalle

1
cpppreference en enlaces estructurados es.cppreference.com/w/cpp/language/structured_binding
TankorSmash

Si está compilando con GCC, necesita la versión 7 o superior para enlaces estructurados: gcc.gnu.org/projects/cxx-status.html
csknk

25

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

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

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

Entonces puede ver claramente lo que hay abcen su caso std::pair<key_type, value_type >. Entonces, para imprimir, puede acceder a cada elemento mediante abc.firstyabc.second



3

Si el operador de asignación de copias de foo y bar es barato (por ejemplo, int, char, puntero, etc.), puede hacer lo siguiente:

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

44
El primer fragmento de código no está usando un "C ++ 11 basado en rango para ()". No es una respuesta a "C ++ 11: ¿cómo utilizar el bucle for () basado en rango con std :: map?"
isoiphone

1
@ytj Ya se menciona en la respuesta que no funciona. No quiero eliminar eso para que los nuevos usuarios no tengan que probarlo y descubrir el hecho nuevamente.
balki
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.