std :: mapで範囲ベースのfor()ループを使用する方法


336

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


4
ステートメントの範囲は、標準ライブラリstd::beginstd::end同じ名前の関数またはメンバー関数で不誠実なダンスをします。
ジーンブシュエフ2011

10
@will 3行の例では、偽の変数名に追いついていますか?
ステファン・

回答:


495

コンテナの各要素map<K, V>::value_typeは、typedeffor std::pair<const K, V>です。したがって、C ++ 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;
}

値を変更する予定がない場合。

C ++ 11およびC ++ 14では、拡張forループを使用して各ペアを独自に抽出し、キーと値を手動で抽出できます。

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

値の読み取り専用ビューが必要kvconst場合は、変数をマークすることも検討できます。


95

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

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

const &キーにを取得することは可能ですが、値への非const参照ですか?(それがmap :: value_typeが行うことなので...)
peterchen

2
@peterchen:kあるconstあなたが使用している場合for(auto&[k,v]:testing)
dalle


GCCでコンパイルしている場合、構造化バインディングにはバージョン7以上が必要です。gcc.gnu.org
projects

25

このペーパーから: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-specier-seq simple-declarator(*begin);
        statement
    }
}

だからあなたはabcあなたのケースにあるものがどうなるかをはっきりと見ることができますstd::pair<key_type, value_type >。だから、あなたがすることで、アクセスに各要素を行うことができます印刷するabc.firstと、abc.second



3

fooとbarのコピー代入演算子が安価な場合(たとえば、int、char、ポインタなど)、次のことができます。

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

4
コードの最初のスニペットは、「C ++ 11範囲ベースのfor()」を使用していません。「C ++ 11:std :: mapで範囲ベースのfor()ループを使用する方法」に対する答えではありません。
isoiphone

1
@ytj動作しないという回答ですでに言及されています。私はそれを削除したくないので、新しいユーザーがそれを試して、事実をもう一度知る必要はありません。
バルキ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.