¿Cómo utilizar el bucle for() basado en rango con std::map?
El ejemplo común para bucles for() basados en rangos 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 xyz
es un int
. Pero, ¿qué pasa cuando tenemos algo así como un mapa? ¿Cuál es el tipo de 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 for() 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 desreferenciarlo de todos modos.
Pero no sé 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 rangos están en g++ 4.6+, así que no he tenido la oportunidad de probarlo todavía).
Cada elemento del contenedor es un map<K, V>::value_type
, que es un typedef
for std::pair<const K, V>
. En consecuencia, en C++ 17 o superior, puedes 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 planea modificar los valores.
En C++11 y C++14, puede usar for
bucles mejorados para extraer cada par por sí solo y 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 kv
variable const
si desea una vista de solo lectura de los valores.
En C++17 esto se denomina enlaces estructurados , que permiten 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<C>::begin(rng)), end(std::For<C>::end(rng)); begin != end; ++ begin) {
type-specifier-seq simple-declarator(*begin);
statement
}
}
Así podrás ver claramente que abc
será lo que sucede en tu caso std::pair<key_type, value_type >
. Entonces, para imprimir, puede acceder a cada elemento mediante abc.first
yabc.second
Si el operador de asignación de copia de foo y bar es económico (por ejemplo, int, char, pointer, etc.), puedes hacer lo siguiente:
foo f; bar b;
BOOST_FOREACH(boost::tie(f,b),testing)
{
cout << "Foo is " << f << " Bar is " << b;
}