Общим примером для циклов 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+, поэтому у меня еще не было возможности попробовать его.)
Ответ 1
Каждый элемент контейнера представляет собой map<K, V>::value_type
, которая является typedef
для std::pair<const K, V>
. Следовательно, в С++ 17 или выше, вы можете написать
for (auto& [key, value]: myMap) {
std::cout << key << " has value " << value << std::endl;
}
или как
for (const auto& [key, value]: myMap) {
std::cout << key << " has value " << value << std::endl;
}
если вы не планируете изменять значения.
В С++ 11 и С++ 14 вы можете использовать расширенные циклы for
для извлечения каждой пары самостоятельно, а затем вручную извлекать ключи и значения:
for (auto& kv : myMap) {
std::cout << kv.first << " has value " << kv.second << std::endl;
}
Вы также можете пометить переменную kv
const
если хотите просматривать значения только для чтения.
Ответ 2
В С++ 17 это называется структурированные привязки, что позволяет:
std::map< foo, bar > testing = { /*...blah...*/ };
for ( const auto& [ k, v ] : testing )
{
std::cout << k << "=" << v << "\n";
}
Ответ 3
Из этой статьи: 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
Ответ 4
Если вы хотите видеть только ключи/значения на карте и как использовать 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
Ответ 5
Если оператор копирования foo и bar является дешевым (например, int, char, указатель и т.д.), Вы можете сделать следующее:
foo f; bar b;
BOOST_FOREACH(boost::tie(f,b),testing)
{
cout << "Foo is " << f << " Bar is " << b;
}