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

El ejemplo común para C ++ 11 basado en el rango para () loops es siempre algo simple como esto:

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

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

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

Cuando el contenedor que se atraviesa es algo simple, parece que los bucles () basados ​​en rangos nos darán cada elemento, no un iterador. Lo cual es bueno … si fuera un iterador, lo primero que siempre tendríamos que hacer es eliminarlo 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 los bucles basados ​​en rango están en g ++ 4.6+, así que no he tenido la oportunidad de probarlo todavía).

Cada elemento del contenedor es un map::value_type , que es un typedef para std::pair . En consecuencia, escribirías esto como

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

Para mayor eficiencia, es una buena idea hacer que el parámetro en el bucle sea una referencia. También podría considerar hacer que const si desea una vista de solo lectura de los valores.

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

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

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

Entonces puedes ver claramente que lo que es abc en tu caso será std::pair . Para imprimir, puede acceder a cada elemento mediante abc.first y abc.second

Si solo desea ver las claves / valores de su mapa y desea usar el refuerzo, puede usar los adaptadores de impulso con los bucles basados ​​en el rango:

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

hay un impulso equivalente :: adaptadores :: valores_claves

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

Si el operador de asignación de copia de foo y barra 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; } 

EDITAR : Lo siguiente no funciona como antes : tiene que ser una statement , no una expresión lvalue .

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