Aralık tabanlı () döngü için std :: map ile nasıl kullanılır?


336

() Döngüleri için C ++ 11 aralık tabanlı genel örnek her zaman böyle basit bir şeydir:

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

Bu durumda xyzbir int. Fakat harita gibi bir şeyimiz olduğunda ne olur? Bu örnekteki değişkenin türü nedir:

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

Geçilen kap basit bir şey olduğunda, () döngüler için aralık tabanlı bir yineleyici değil bize her öğeyi verecek gibi görünüyor. Bu güzel ... eğer yineleyici olsaydı, her zaman yapmamız gereken ilk şey yine de dereference.

Ancak, haritalar ve multimaps gibi şeyler söz konusu olduğunda ne olacağı konusunda kafam karıştı.

(Aralık tabanlı döngüler g ++ 4.6+ içindeyken hala g ++ 4.4 kullanıyorum, bu yüzden henüz deneme şansım olmadı.)


4
İfade aralığı, standart kütüphane std::beginve std::endişlevler veya aynı işlev altındaki üye işlevleriyle kutsal bir dans eder .
Gene Bushuyev

10
@will 3 satırlı bir örnekte, sahte değişken adına yakalanıyor musunuz?
Stéphane

Yanıtlar:


495

Kabın her bir öğesi map<K, V>::value_typebir typedeffor'dur std::pair<const K, V>. Sonuç olarak, C ++ 17 veya daha yüksek sürümlerde,

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

veya gibi

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

değerleri değiştirmeyi planlamıyorsanız.

C ++ 11 ve C ++ 14'te, forher çifti kendi başına ayıklamak için gelişmiş döngüler kullanabilir , ardından anahtarları ve değerleri manuel olarak ayıklayabilirsiniz:

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

Değerlerin salt okunur bir görünümünü istiyorsanız kvdeğişkeni işaretlemeyi de düşünebilirsiniz const.


95

C ++ 17'de buna aşağıdakilere izin veren yapısal bağlamalar denir :

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

Bir const &anahtara ulaşmak mümkün mü, ancak değere const olmayan bir başvuru? (çünkü bu harita :: değer_türü yapar ...)
peterchen

2
@peterchen: kolup constkullanırsanızfor(auto&[k,v]:testing)
dalle


GCC ile derliyorsanız, yapılandırılmış ciltlemeler için sürüm 7 veya daha iyisine ihtiyacınız vardır: gcc.gnu.org/projects/cxx-status.html
csknk

25

Bu makaleden: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf

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

sözdizimsel olarak eşittir

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

Açıkça görebiliriz Yani ne abcsenin böyle olacaktır içinde std::pair<key_type, value_type >. Böylece yazdırma için her öğeye abc.firstveabc.second



3

Foo ve çubuğun kopya atama operatörü ucuzsa (örn. İnt, char, pointer vb.), Aşağıdakileri yapabilirsiniz:

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

4
İlk kod snippet'i, () için "C ++ 11 aralığına dayalı" kullanmıyor. "C ++ 11: std :: map ile aralık tabanlı () döngü için nasıl kullanılır?"
isoiphone

1
@ytj Yanıtta işe yaramadığı zaten belirtilmiş. Bunu kaldırmak istemiyorum, böylece yeni kullanıcılar denemek ve gerçeği tekrar öğrenmek zorunda kalmıyor.
balki
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.