Как использовать диапазон для цикла() с std:: map?

Общим примером для циклов for() для С++ 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(), основанные на диапазонах, будут давать нам каждый элемент, а не итератор. Что хорошо... если бы это был итератор, первое, что нам всегда нужно было сделать, это разыгрывать его в любом случае.

Но я смущен относительно того, что ожидать, когда дело доходит до таких вещей, как карты и мультимаксы.

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

296
06 авг. '11 в 3:12
источник поделиться
5 ответов

Каждый элемент контейнера представляет собой 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 если вы хотите просмотр значений только для чтения.

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

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

который намного чище.

419
06 авг. '11 в 3:15
источник

Связанные вопросы


Похожие вопросы

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

std::map< foo, bar > testing = { /*...blah...*/ };
for ( const auto& [ k, v ] : testing )
{
  std::cout << k << "=" << v << "\n";
}
89
01 дек. '16 в 18:05
источник

Из этой статьи: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/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

25
06 авг. '11 в 3:24
источник

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

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

существует эквивалентный boost:: adapters:: key_values ​​

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

13
26 июня '14 в 11:31
источник

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

foo f; bar b;
BOOST_FOREACH(boost::tie(f,b),testing)
{
  cout << "Foo is " << f << " Bar is " << b;
}
2
22 янв. '13 в 21:48
источник

Посмотрите другие вопросы по меткам или Задайте вопрос