405

The common example for C++11 range-based for() loops is always something simple like this:

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

In which case xyz is an int. But, what happens when we have something like a map? What is the type of the variable in this example:

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

When the container being traversed is something simple, it looks like range-based for() loops will give us each item, not an iterator. Which is nice...if it was iterator, first thing we'd always have to do is to dereference it anyway.

But I'm confused as to what to expect when it comes to things like maps and multimaps.

(I'm still on g++ 4.4, while range-based loops are in g++ 4.6+, so I haven't had the chance to try it yet.)

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Stéphane
  • 19,459
  • 24
  • 95
  • 136
  • 7
    The range for statement does an unholy dance with the standard library `std::begin` and `std::end` functions or member functions under the same name. – Gene Bushuyev Aug 07 '11 at 01:55
  • 11
    @will On a 3-line example, you're getting caught up on the fake variable name? – Stéphane Feb 28 '17 at 21:03

5 Answers5

606

Each element of the container is a map<K, V>::value_type, which is a typedef for std::pair<const K, V>. Consequently, in C++17 or higher, you can write

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

or as

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

if you don't plan on modifying the values.

In C++11 and C++14, you can use enhanced for loops to extract out each pair on its own, then manually extract the keys and values:

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

You could also consider marking the kv variable const if you want a read-only view of the values.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • Related links I've found really helpful as I've studied this, in this order from most-to-least helpful: 1) [MOST EXCELLENT article] https://thispointer.com/how-to-iterate-over-an-unordered_map-in-c11/, 2) [EXCELLENT GENERAL INFO on iterators] https://www.cplusplus.com/reference/iterator/, 3) [cplusplus.com `std::unordered_map` reference pg] https://www.cplusplus.com/reference/unordered_map/unordered_map/, 4) [cppreference.com `std::unordered_map` reference pg] https://en.cppreference.com/w/cpp/container/unordered_map, 5) see also [my answer here](https://stackoverflow.com/a/66164132/4561887). – Gabriel Staples Feb 11 '21 at 23:09
  • the last edit, adding `const` in the last code example, is unnecessary and does not fit with the author's original context. Also, it's not idiomatic to put `const` at that position every time. E.g., you should *not* use `const` if you want to modify the values or call the non-const method. – starriet Aug 18 '22 at 14:30
  • Also note that we can't use both `std::map::value_type` and `std::pair` for structured binding declaration(e.g. `[key, value]`). – starriet Aug 18 '22 at 14:36
105

In C++17 this is called structured bindings, which allows for the following:

std::map< foo, bar > testing = { /*...blah...*/ };
for ( const auto& [ k, v ] : testing )
{
  std::cout << k << "=" << v << "\n";
}
dalle
  • 18,057
  • 5
  • 57
  • 81
  • Ist it possible to get a `const &` to the key, but a non-const reference to the value? (because that's what map::value_type does...) – peterchen Nov 08 '17 at 17:03
  • 4
    @peterchen: `k` is `const` if you use `for(auto&[k,v]:testing)` – dalle Nov 14 '17 at 09:18
  • 2
    cpppreference on structured bindings http://en.cppreference.com/w/cpp/language/structured_binding – TankorSmash Dec 14 '17 at 03:06
  • If you're compiling with GCC you need version 7 or better for structured bindings: https://gcc.gnu.org/projects/cxx-status.html – csknk Jul 15 '18 at 12:33
28

From this paper: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf

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

is syntactically equivalent to

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

So you can clearly see that what is abc in your case will be std::pair<key_type, value_type >. So for printing you can do access each element by abc.first and abc.second

ForceBru
  • 43,482
  • 10
  • 63
  • 98
A. K.
  • 34,395
  • 15
  • 52
  • 89
16

If you only want to see the keys/values from your map and like using boost, you can use the boost adaptors with the range based loops:

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

there is an equivalent boost::adaptors::key_values

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

Pixie-Poop
  • 171
  • 1
  • 4
3

If copy assignment operator of foo and bar is cheap (eg. int, char, pointer etc), you can do the following:

foo f; bar b;
BOOST_FOREACH(boost::tie(f,b),testing)
{
  cout << "Foo is " << f << " Bar is " << b;
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
balki
  • 26,394
  • 30
  • 105
  • 151
  • 4
    First snippet of code is not using a "C++11 range-based for()". It is not an answer to "C++11: how to use range-based for() loop with std::map?" – isoiphone Feb 01 '14 at 04:54
  • 1
    @ytj It is already mentioned in the answer that it doesn't work. I don't want to remove that so that new users don't have to try it and find out the fact again. – balki Jul 03 '14 at 15:11