首页 文章

如何使用基于范围的for()循环与std :: map?

提问于
浏览
284

基于C 11范围的()循环的常见示例总是这样简单:

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

在这种情况下 xyzint . 但是,当我们有像 Map 这样的东西时会发生什么?此示例中变量的类型是什么:

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

当遍历的容器很简单时,看起来基于范围的()循环将给我们每个项目,而不是迭代器 . 哪个好...如果它是迭代器,我们总是要做的第一件事就是取消引用它 .

但是,当涉及 Map 和多图等事情时,我很困惑 .

(我仍然在使用4.4,而基于范围的循环在g 4.6中,所以我还没有机会尝试它 . )

5 回答

  • 86

    容器的每个元素都是 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;
    }
    

    哪个更干净 .

  • 13

    在C 17中,这称为structured bindings,它允许以下内容:

    std::map< foo, bar > testing = { /*...blah...*/ };
    for ( const auto& [ k, v ] : testing )
    {
      std::cout << k << "=" << v << "\n";
    }
    
  • 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-specifier-seq simple-declarator(*begin);
            statement
        }
    }
    

    所以你可以清楚地看到你的案例中的 abc 将是 std::pair<key_type, value_type > . 因此,对于打印,您可以通过 abc.firstabc.second 访问每个元素

  • 397

    如果您只想查看 Map 中的键/值并使用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

  • 2

    如果foo和bar的复制赋值运算符很便宜(例如int,char,pointer等),则可以执行以下操作:

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

    编辑:以下不像以前那样 : ,它必须是 declaration ,而不是 lvalue expression .

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

相关问题