Как использовать диапазон для () цикла с std :: map? - PullRequest
305 голосов
/ 06 августа 2011

Типичным примером для циклов for () на основе диапазона в C ++ 11 всегда является что-то простое:

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

В этом случае xyz является int.Но что происходит, когда у нас есть что-то вроде карты?Каков тип переменной в этом примере:

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

Когда просматриваемый контейнер является чем-то простым, похоже, что циклические циклы for () дадут нам каждый элемент, а не итератор.Что неплохо ... если бы это был итератор, первое, что мы всегда должны были бы сделать, - это разыменовать его.multimaps.

(я все еще на g ++ 4.4, в то время как циклы на основе диапазона находятся в g ++ 4.6+, поэтому у меня еще не было возможности попробовать это).

Ответы [ 5 ]

435 голосов
/ 06 августа 2011

Каждый элемент контейнера представляет собой map<K, V>::value_type, то есть typedef для std::pair<const K, V>.Следовательно, вы бы написали это как

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

. Для эффективности рекомендуется сделать параметр в цикле ссылкой.Вы также можете рассмотреть возможность сделать его const, если вы хотите просматривать значения только для чтения.

Начиная с C ++ 17, вы также можете написать

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

, который являетсямного чище.

91 голосов
/ 01 декабря 2016

В C ++ 17 это называется структурированные привязки , что допускает следующее:

std::map< foo, bar > testing = { /*...blah...*/ };
for ( const auto& [ k, v ] : testing )
{
  std::cout << k << "=" << v << "\n";
}
25 голосов
/ 06 августа 2011

Из этого документа: http://www.open -std.org / jtc1 / sc22 / wg21 / docs /apers / 2006 / n2049.pdf

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

синтаксически эквивалентно

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

Таким образом, вы можете ясно видеть, что abc в вашем случае будет std::pair<key_type, value_type >. Таким образом, для печати вы можете получить доступ к каждому элементу с помощью abc.first и abc.second

14 голосов
/ 26 июня 2014

Если вы хотите видеть только ключи / значения на вашей карте и вам нравится использовать повышение, вы можете использовать адаптеры повышения с петлями на основе диапазона:

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

есть эквивалентный импульс :: адаптеры :: key_values ​​

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

3 голосов
/ 22 января 2013

Если оператор присваивания копии foo и bar дешев (например, int, char, указатель и т. Д.), Вы можете сделать следующее:

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