如何在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
statement的范围与标准库std::beginstd::end同名的函数或成员函数发生了恶意冲突。
Gene Bushuyev 2011年

10
@will在3行示例中,您是否陷入了虚假的变量名?
斯特凡

Answers:


494

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

如果您需要值的只读视图,也可以考虑标记kv变量const


95

在C ++ 17中,这称为结构化绑定,它允许以下操作:

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

是否有可能获得const &键,但非常量引用值?(因为那是map :: value_type的功能...)
peterchen

2
@peterchen:kconst,如果你使用for(auto&[k,v]:testing)
装饰板


如果使用GCC进行编译,则需要版本7或更高版本的结构化绑定:gcc.gnu.org/projects/cxx-status.html
csknk

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,pointer等),则可以执行以下操作:

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

4
第一个代码段未使用“基于C ++ 11范围的for()”。这不是对“ C ++ 11:如何将基于范围的for()循环与std :: map一起使用?”的答案。
isoiphone 2014年

1
@ytj答案中已经提到它不起作用。我不想删除它,以便新用户不必尝试它并再次发现事实。
巴尔基2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.