Jak używać pętli for () opartej na zakresie ze std :: map?


336

Typowym przykładem pętli opartych na zakresie C ++ 11 dla () jest zawsze coś takiego:

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

W którym xyzto przypadku jest int. Ale co się dzieje, gdy mamy coś w rodzaju mapy? Jaki jest typ zmiennej w tym przykładzie:

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

Gdy kontener, przez który przechodzi się, jest czymś prostym, wygląda na to, że pętle oparte na zakresie dla () dadzą nam każdy element, a nie iterator. Co jest miłe ... gdyby to był iterator, pierwszą rzeczą, którą zawsze musielibyśmy zrobić, to zrezygnować z niego.

Ale jestem zdezorientowany, czego się spodziewać, jeśli chodzi o takie rzeczy jak mapy i multimapy.

(Nadal używam g ++ 4.4, podczas gdy pętle oparte na zakresie są w g ++ 4.6+, więc nie miałem jeszcze okazji tego wypróbować.)


4
Zakres instrukcji wykonuje niecny taniec ze standardową biblioteką std::begini std::endfunkcjami lub funkcjami składowymi o tej samej nazwie.
Gene Bushuyev,

10
@will W 3-wierszowym przykładzie łapiesz się na fałszywej nazwie zmiennej?
Stéphane

Odpowiedzi:


495

Każdy element zbiornika jest map<K, V>::value_type, co jest typedefna std::pair<const K, V>. W związku z tym w C ++ 17 lub nowszym możesz pisać

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

lub jako

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

jeśli nie planujesz modyfikować wartości.

W C ++ 11 i C ++ 14 można użyć rozszerzonych forpętli do samodzielnego wyodrębnienia każdej pary, a następnie ręcznie wyodrębnić klucze i wartości:

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

Możesz również rozważyć oznaczenie kvzmiennej, constjeśli chcesz zobaczyć wartości tylko do odczytu.


95

W C ++ 17 nazywa się to powiązaniami strukturalnymi , co pozwala na:

std::map< foo, bar > testing = { /*...blah...*/ };
for ( const auto& [ k, v ] : testing )
{
  std::cout << k << "=" << v << "\n";
}

Czy można uzyskać const &klucz, ale nie stałe odniesienie do wartości? (ponieważ to właśnie robi mapa :: typ_wartości ...)
peterchen

2
@peterchen: kis constif you usefor(auto&[k,v]:testing)
dalle

1
cpppreference na temat powiązań strukturalnych en.cppreference.com/w/cpp/language/structured_binding
TankorSmash

Jeśli kompilujesz za pomocą GCC, potrzebujesz wersji 7 lub lepszej dla powiązań strukturalnych: gcc.gnu.org/projects/cxx-status.html
csknk

25

Z tego artykułu: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf

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

jest składniowo równoważny z

{
    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-specier-seq simple-declarator(*begin);
        statement
    }
}

Możesz więc wyraźnie zobaczyć, że tak będzie abcw twoim przypadku std::pair<key_type, value_type >. Aby wydrukować, możesz uzyskać dostęp do każdego elementu za pomocą abc.firstiabc.second



3

Jeśli operator przypisywania kopii foo i paska jest tani (np. Int, char, wskaźnik itp.), Możesz wykonać następujące czynności:

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

4
Pierwszy fragment kodu nie używa „C ++ 11 opartego na zakresie dla ()”. To nie jest odpowiedź na „C ++ 11: jak używać pętli opartej na zakresie dla () ze std :: map?”
isoiphone

1
@ytj W odpowiedzi wspomniano już, że to nie działa. Nie chcę tego usuwać, aby nowi użytkownicy nie musieli tego próbować i ponownie dowiedzieć się o tym.
balki
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.