How to use range-based for() loop with std::map?
C++ 11基于距离的(f)循环的常见例子总是这样简单的:
1 2 3 4 5 | std::vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7 }; for ( auto xyz : numbers ) { std::cout << xyz << std::endl; } |
在这种情况下,
1 2 3 4 5 6 | 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+,所以我还没有机会尝试它。)
容器的每个元素都是一个
1 2 3 | for (auto& kv : myMap) { std::cout << kv.first <<" has value" << kv.second << std::endl; } |
为了提高效率,最好将循环中的参数作为参考。如果需要值的只读视图,也可以考虑将其设置为
从C++ 17开始,你也可以写
1 2 3 | for (auto& [key, value]: myMap) { std::cout << key <<" has value" << value << std::endl; } |
更干净。
在C++ 17中,这被称为结构化绑定,它允许以下内容:
1 2 3 4 5 6 | std::map< foo, bar > testing = { /*...blah...*/ }; for ( const auto& [ k, v ] : testing ) { std::cout << k <<"=" << v <<" "; } |
本文来源:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2049.pdf
在语法上等价于
1 2 3 4 5 6 7 8 | { 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-speci?er-seq simple-declarator(*begin); statement } } |
所以你可以清楚地看到,在你的例子中,
如果您只想从地图中查看键/值,如使用Boost,则可以将Boost适配器与基于范围的循环一起使用:
1 2 3 4 | for (const auto& value : myMap | boost::adaptors::map_values) { std::cout << value << std::endl; } |
有一个等效的boost::adaptors::key_值
http://www.boost.org/doc/libs/1_51_0/libs/range/doc/html/range/reference/adaptors/reference/map_values.html
如果foo和bar的copy assignment操作符很便宜(例如int、char、pointer等),则可以执行以下操作:
1 2 3 4 5 | foo f; bar b; BOOST_FOREACH(boost::tie(f,b),testing) { cout <<"Foo is" << f <<" Bar is" << b; } |