web-dev-qa-db-ja.com

std :: mapでrange-based for()ループを使うにはどうすればいいですか?

C++ 11の範囲ベースのfor()ループの一般的な例は、常に次のような単純なものです。

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

その場合xyzintです。しかし、地図のようなものがあるとどうなりますか?この例の変数の型は何ですか:

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+に入っているので、まだ試す機会がありませんでした。)

301
Stéphane

コンテナの各要素はmap<K, V>::value_typeで、これはstd::pair<const K, V>typedefです。したがって、これを次のように書きます。

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

これはずっときれいです。

429
templatetypedef

C++ 17では、これは 構造化バインディング と呼ばれ、次のことが可能になります。

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

この論文から: 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
    }
}

ですから、あなたのケースでabcstd::pair<key_type, value_type >になることがはっきりわかります。それで、印刷のためにあなたはabc.firstabc.secondによって各要素にアクセスすることができます

25
A. K.

マップからキー/値のみを表示したい場合や、boostを使用したい場合は、範囲ベースのループで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
Pixie-Poop

Fooとbarのコピー代入演算子が安い場合(例:int、char、pointerなど)、次のことができます。

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