lambda签名for_each + unordered_map

时间:2013-06-25 20:16:59

标签: c++ c++11

#include <unordered_map>
#include <string>
#include <iostream>
#include <algorithm>
#include <utility>

int main() 
{
  std::unordered_map<string, int> hash {{"a", 1}, {"b", 2}, {"c", 3}};

  // CaseA(NO-ERROR)
  std::for_each(hash.begin(), hash.end(),
    [](const std::pair<string, int>& p) {
      std::cout << p.first << " => " << p.second << endl;
    }
  );

  // CaseB(NO-ERROR)
  std::for_each(hash.begin(), hash.end(),
    [](const std::pair<string, int> p) {
      std::cout << p.first << " => " << p.second << endl;
    }
  );

  // CaseC(NO-ERROR)
  std::for_each(hash.begin(), hash.end(),
    [](std::pair<string, int> p) {
      std::cout << p.first << " => " << p.second << endl;
    }
  );

  // CaseD(ERROR)
  std::for_each(hash.begin(), hash.end(),
    [](std::pair<string, int>& p) {
      std::cout << p.first << " => " << p.second << endl;
    }
  );

}

Q1&GT; 为什么CaseD错了?

Q2&GT; CaseA是推荐的方式吗?

谢谢

2 个答案:

答案 0 :(得分:13)

value_type的{​​{1}}为std::unordered_map<K,V>(请注意std::pair<const K,V>)。 您无法将类型为const的引用绑定到类型为std::pair<K,V>的对象。您应该使用std::pair<const K,V>而不是直接拼写该类型的名称,因为这样可以确保您没有弄错。

如果您想知道,案例C的工作原理是因为有一个构造函数可以转换类型,因此std::unordered_map<K,V>::value_type将是p中值的副本。

对于不打算修改容器中元素的lambda的推荐方式是:

std::unordered_map

在问题的前3个案例中,完成了元素的复制(性能命中)。从调用者的角度来看,案例B和C是相同的(在一个函数中,顶级限定符被删除),但从lambda案例B的定义的角度来看,将确保你没有尝试修改参数(它本身就是源的副本)

答案 1 :(得分:5)

您的问题是您的容器已满std::pair<const string, int>。对于案例1到3,容器中的std::pair<const string, int>可以隐式转换为std::pair<string, int>,然后临时传递给lambda。

C ++ 11中建议的方法是对容器的每个元素执行非变异操作:

for( auto const& p: hash ) {
  std::cout << p.first << " => " << p.second << endl;
}

更简洁,并且不违反DRY。当有意义时,首选基于容器的迭代而不是基于迭代器的迭代。

在基于容器的std::算法和auto类型的lambda之间,使用std::算法将在C ++的一个或两个版本中再次变得更具诱惑力。即便如此,除非你抽象使用lambda的算法,for_each现在还很值得怀疑,因为我们有一流的语言功能可以完成for_each的工作。